Skip to content

Commit

Permalink
feat(widget): timeline view nodes are reflective of actual nodes (#172)
Browse files Browse the repository at this point in the history
* Also fixes styling of the widget, which previously tried to modify its host element, leading to a world of hurt.
  • Loading branch information
andrewedstrom authored Nov 20, 2023
1 parent 2fe4d7c commit cfb974a
Show file tree
Hide file tree
Showing 9 changed files with 301 additions and 232 deletions.
16 changes: 3 additions & 13 deletions packages/widget/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,15 @@
<link rel='icon' type='image/svg+xml' href='/vite.svg' />
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
<title>Vite + Lit + TS</title>
<link rel='stylesheet' href='./src/index.css' />
<script type='module' src='/src/docmaps-widget.ts'></script>
</head>
<body>

<p>
10.15252/rc.2022616985
10.1101/273730
</p>
<docmaps-widget serverurl='http://localhost:8080' doi='10.15252/rc.2022616985'></docmaps-widget>
<docmaps-widget serverurl='https://web-nodejs.onrender.com' doi='10.1101/273730'></docmaps-widget>
<br>
<br>
<p>
10.1101/2022.11.08.515698
</p>
<docmaps-widget serverurl='http://localhost:8080' doi='10.1101/2022.11.08.515698'></docmaps-widget>
<br>
<br>
<p>
10.1101/2022.11.08.569420
</p>
<docmaps-widget serverurl='http://localhost:8080' doi='10.1101/2022.11.08.569420'></docmaps-widget>
</body>
</html>
57 changes: 57 additions & 0 deletions packages/widget/src/assets/detail-navigation-header.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { nothing, svg, SVGTemplateResult } from 'lit';
import { DisplayObject, TYPE_DISPLAY_OPTIONS } from '../constants';

const backButton: SVGTemplateResult = svg`
<svg width='36' height='36' viewBox='0 0 36 36' fill='none' xmlns='http://www.w3.org/2000/svg'>
<circle cx='17.5' cy='17.5' r='17' stroke='#474747'/>
<path transform='scale(-1,1) translate(-35,0)' d='M22.5 17.134C23.1667 17.5189 23.1667 18.4811 22.5 18.866L10.5 25.7942C9.83333 26.1791 9 25.698 9 24.9282L9 11.0718C9 10.302 9.83333 9.82087 10.5 10.2058L22.5 17.134Z' fill='#474747'/>
<path transform='scale(-1,1) translate(-35,0)' d='M24 10L24 26' stroke='#474747' stroke-width='2' stroke-linecap='round'/>
<!-- <circle cx='24' cy='18' r='3' fill='#474747'/>-->
</svg>`;

const forwardButton: SVGTemplateResult = svg`
<svg width='36' height='36' viewBox='0 0 36 36' fill='none' xmlns='http://www.w3.org/2000/svg'>
<circle cx='17.5' cy='17.5' r='17' stroke='#474747'/>
<path d='M22.5 17.134C23.1667 17.5189 23.1667 18.4811 22.5 18.866L10.5 25.7942C9.83333 26.1791 9 25.698 9 24.9282L9 11.0718C9 10.302 9.83333 9.82087 10.5 10.2058L22.5 17.134Z' fill='#474747'/>
<path d='M24 10L24 26' stroke='#474747' stroke-width='2' stroke-linecap='round'/>
<!-- <circle cx='24' cy='18' r='3' fill='#474747'/>-->
</svg>`;

const makeTimeline = (allNodes: DisplayObject[], selectedNode: DisplayObject) => {
const width = 368;
const firstXPosition: number = 6.5;
const lastXPosition: number = 358.5;

const timelineNodes = allNodes.map((node, i) => {
let x = firstXPosition;
if (i > 0) {
const spaceBetweenNodes: number = (lastXPosition - firstXPosition) / (allNodes.length - 1);
x = firstXPosition + spaceBetweenNodes * i;
}
const displayOpts = TYPE_DISPLAY_OPTIONS[node.type];
const color = displayOpts.detailBackgroundColor ?? displayOpts.backgroundColor;

const selectedNodeIndicator =
node.nodeId === selectedNode.nodeId
? svg`<circle class='selected-node-outline' cx='${x}' cy='6.5' r='5.5' stroke='${color}'/> <path class='selected-node-line' d='M${x} 7L${x} 35' stroke='${color}' stroke-linecap='round'/>`
: nothing;
return svg`
<circle class='timeline-node' cx='${x}' cy='6.5' r='3.5' fill='${color}'/>
${selectedNodeIndicator}
`;
});

return svg`
<svg width='${width}' height='35' viewBox='0 0 ${width} 35' fill='none' xmlns='http://www.w3.org/2000/svg' style='align-self: end;'>
<line x1='3' y1='6.75' x2='${width - 6}' y2='6.75' stroke='#777777' stroke-width='0.5'/>
${timelineNodes}
</svg>`;
};

export const renderDetailNavigationHeader: (
allNodes: DisplayObject[],
selectedNode: DisplayObject,
) => SVGTemplateResult = (allNodes: DisplayObject[], selectedNode: DisplayObject) => svg`
${backButton}
${forwardButton}
${makeTimeline(allNodes, selectedNode)}`;
2 changes: 1 addition & 1 deletion packages/widget/src/assets/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// All files which will be accessible when the widget is installed via npm are declared here
export * from './close-details-button';
export * from './logo';
export * from './timeline-placeholder';
export * from './detail-navigation-header';
35 changes: 0 additions & 35 deletions packages/widget/src/assets/timeline-placeholder.ts

This file was deleted.

12 changes: 6 additions & 6 deletions packages/widget/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const TYPE_DISPLAY_OPTIONS: {
review: {
shortLabel: 'R',
longLabel: 'Review',
backgroundColor: '#222F46',
backgroundColor: '#1E2F48',
textColor: '#D7E4FD',
},
preprint: {
Expand All @@ -48,19 +48,19 @@ export const TYPE_DISPLAY_OPTIONS: {
'journal-article': {
shortLabel: 'JA',
longLabel: 'Journal Article',
backgroundColor: '#7B1650',
backgroundColor: '#880052',
textColor: '#FFF',
},
editorial: {
shortLabel: 'ED',
longLabel: 'Editorial',
backgroundColor: '#468580',
backgroundColor: '#2A8781',
textColor: '#FFFFFF',
},
comment: {
shortLabel: 'CO',
longLabel: 'Comment',
backgroundColor: '#AB664E',
backgroundColor: '#B66248',
textColor: '#FFF',
},
reply: {
Expand All @@ -72,10 +72,10 @@ export const TYPE_DISPLAY_OPTIONS: {
'??': {
shortLabel: '',
longLabel: 'Type unknown',
backgroundColor: '#EFEFEF',
backgroundColor: '#CDCDCD',
textColor: '#043945',
detailBackgroundColor: '#777',
detailTextColor: '#EFEFEF',
detailTextColor: '#CDCDCD',
dottedBorder: true,
},
};
Expand Down
48 changes: 26 additions & 22 deletions packages/widget/src/docmaps-widget.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { html, HTMLTemplateResult, LitElement, nothing } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { customCss } from './styles';
import { closeDetailsButton, logo, timelinePlaceholder } from './assets';
import { closeDetailsButton, logo, renderDetailNavigationHeader } from './assets';
import * as d3 from 'd3';
import { Task } from '@lit/task';
import { DocmapFetchingParams, getDocmap } from './docmap-controller';
Expand All @@ -23,7 +23,6 @@ import {
WIDGET_SIZE,
} from './constants';

// TODO name should be singular not plural
@customElement('docmaps-widget')
export class DocmapsWidget extends LitElement {
@property({ type: String })
Expand All @@ -35,6 +34,9 @@ export class DocmapsWidget extends LitElement {
@state()
selectedNode?: DisplayObject;

@state()
allNodes: DisplayObject[] = [];

#docmapFetchingTask: Task<DocmapFetchingParams, DisplayObjectGraph> = new Task(
this,
getDocmap,
Expand All @@ -48,28 +50,30 @@ export class DocmapsWidget extends LitElement {
}

render(): HTMLTemplateResult {
const content: HTMLTemplateResult = this.selectedNode
? this.renderDetailsView(this.selectedNode)
: html` <div id="tooltip" class="tooltip" style="opacity:0;"></div>
${this.#docmapFetchingTask.render({
complete: this.renderDocmap.bind(this),
})}`;
let content: HTMLTemplateResult;
if (this.selectedNode) {
content = this.renderDetailsView(this.selectedNode);
} else {
content = html`
<div id='tooltip' class='tooltip' style='opacity:0;'></div>
${this.#docmapFetchingTask.render({ complete: this.renderDocmap.bind(this) })}`;
}

return html`
<div class="widget-header">
${logo}
<span>DOCMAP</span>
<div class='docmaps-widget'>
<div class='widget-header'>
${logo}
<span>DOCMAP</span>
</div>
<div id='${GRAPH_CANVAS_ID}'></div>
${content}
</div>
<div id="${GRAPH_CANVAS_ID}"></div>
${content}
`;
}

private renderDocmap({ nodes, edges }: DisplayObjectGraph) {
if (this.shadowRoot) {
this.allNodes = nodes;
const { d3Nodes, d3Edges, graphWidth } = prepareGraphForSimulation(nodes, edges);

const canvas: Element | null = this.getCanvasElement();
Expand Down Expand Up @@ -99,6 +103,7 @@ export class DocmapsWidget extends LitElement {
this.selectedNode = node;
this.requestUpdate(); // Trigger re-render
}

private createEmptySvgForGraph(
canvas: Element | null,
graphWidth: number,
Expand Down Expand Up @@ -168,10 +173,10 @@ export class DocmapsWidget extends LitElement {
});
}

private renderDetailsView(node: DisplayObject): HTMLTemplateResult {
private renderDetailsView(selectedNode: DisplayObject): HTMLTemplateResult {
this.clearGraph();
const opts = TYPE_DISPLAY_OPTIONS[node.type];
const metadataEntries: [string, any][] = this.filterMetadataEntries(node);
const opts = TYPE_DISPLAY_OPTIONS[selectedNode.type];
const metadataEntries: [string, any][] = this.filterMetadataEntries(selectedNode);

const metadataBody: HTMLTemplateResult =
metadataEntries.length > 0
Expand All @@ -182,7 +187,7 @@ export class DocmapsWidget extends LitElement {
const textColor = opts.detailTextColor || opts.textColor;

return html`
<div class="detail-timeline">${timelinePlaceholder}</div>
<div class="detail-timeline">${renderDetailNavigationHeader(this.allNodes, selectedNode)}</div>
<div class="detail-header" style="background: ${backgroundColor};">
<span style="color: ${textColor};"> ${opts.longLabel} </span>
Expand Down Expand Up @@ -308,7 +313,7 @@ function createForceSimulation(d3Nodes: D3Node[], d3Edges: D3Edge[], graphWidth:
// @ts-ignore
return d.nodeId;
})
.distance(RANK_SEPARATION * 1.2)
.distance(RANK_SEPARATION * 1.3)
.strength(0.2),
)
.force('charge', d3.forceManyBody())
Expand Down Expand Up @@ -340,7 +345,6 @@ function setupSimulationTicks(
});
}


// Dagre is a tool for laying out directed graphs. We use it to generate initial positions for
// our nodes, which we then pass to d3 to animate into their final positions.
function getInitialNodePositions(nodes: DisplayObject[], edges: DisplayObjectEdge[]): DagreGraph {
Expand Down
40 changes: 0 additions & 40 deletions packages/widget/src/index.css

This file was deleted.

4 changes: 1 addition & 3 deletions packages/widget/src/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {css, CSSResult} from "lit";

// These are the styles used within the lit component
export const customCss: CSSResult = css`
:host {
.docmaps-widget {
width: 500px;
height: 500px;
background: #EDEDED;
Expand Down Expand Up @@ -101,7 +101,6 @@ export const customCss: CSSResult = css`
.detail-header {
width: 500px;
height: 50px;
outline: 1px solid;
display: flex;
justify-content: space-between;
align-items: center;
Expand Down Expand Up @@ -204,7 +203,6 @@ export const customCss: CSSResult = css`
font-style: normal;
font-weight: 600;
text-anchor: middle;
//letter-spacing: 10px;
text-transform: uppercase;
}
Expand Down
Loading

0 comments on commit cfb974a

Please sign in to comment.