Click on one of the annotations, documents or other wiki elements.
UCE-FEEL
A demonstration of the Unified Corpus Explorer (UCE) for the FEEL project.
Corpora
0
Loading
--> import {ChartJS} from '/js/visualization/chartjs.js'; import {UCEMap} from '/js/visualization/uceMap.js'; import {D3JS} from '/js/visualization/d3js.js'; import {ECharts} from '/js/visualization/echarts.js'; var GraphVizHandler = (function () { GraphVizHandler.prototype.activeCharts = {}; function GraphVizHandler() { console.log('Created GraphViz Handler.'); } GraphVizHandler.prototype.createUceMap = function (target, readonly = false) { const chartId = generateUUID(); const uceMap = new UCEMap(target, readonly); this.activeCharts[chartId] = uceMap; activatePopovers(); return uceMap; } /** * [CHARTJS] -> Creates a pie chart into the given $target (jquery object) */ GraphVizHandler.prototype.createBasicChart = async function (target, title, data, type = null) { const chartId = generateUUID(); let wrapper = document.createElement('div'); wrapper.classList.add('chart-container'); wrapper.setAttribute('data-id', chartId); const canvas = document.createElement('canvas'); const canvasContainer = document.createElement('div'); canvasContainer.classList.add('canvas-container'); canvasContainer.appendChild(canvas); wrapper.appendChild(canvasContainer); const menu = `
`; wrapper.insertAdjacentHTML('beforeend', menu); target.appendChild(wrapper); const jsChart = new ChartJS(canvas, title); jsChart.setData(data); if (type) { jsChart.setType(type); } this.activeCharts[chartId] = jsChart; return jsChart; } GraphVizHandler.prototype.createWordCloud = async function (target, title, wordData) { if (!wordData || !Array.isArray(wordData) || wordData.length === 0) { console.error('Invalid data provided to drawTopicWordCloud:', wordData); return; } target.innerHTML = ''; const cloudContainer = document.createElement('div'); cloudContainer.className = 'word-cloud-container'; if (title) { const titleElement = document.createElement('h5'); titleElement.className = 'word-cloud-title text-center'; titleElement.textContent = title; target.insertBefore(titleElement, target.firstChild); } const maxWeight = Math.max(...wordData.map(item => item.weight)); const minWeight = Math.min(...wordData.map(item => item.weight)); const weightRange = maxWeight - minWeight; wordData.forEach(item => { const word = document.createElement('div'); word.className = 'word-cloud-item'; word.textContent = item.term; const normalizedWeight = weightRange === 0 ? 1 : (item.weight - minWeight) / weightRange; const fontSize = 12 + (normalizedWeight * 24); word.style.fontSize = fontSize + "px"; word.style.cursor = 'default'; word.style.color = getColorForWeight(normalizedWeight); word.addEventListener('mouseover', () => { word.classList.add('hovered'); const tooltip = document.createElement('div'); tooltip.className = 'word-tooltip'; tooltip.textContent = "Weight: " + item.weight.toFixed(4); document.body.appendChild(tooltip); const rect = word.getBoundingClientRect(); tooltip.style.top = (rect.top + word.offsetHeight + 50) + "px"; tooltip.style.left = (rect.left + (word.offsetWidth / 5)) + "px"; tooltip.style.transform = 'translateX(-50%)'; word._tooltip = tooltip; }); word.addEventListener('mouseout', () => { word.classList.remove('hovered'); if (word._tooltip) { word._tooltip.remove(); word._tooltip = null; } }); cloudContainer.appendChild(word); }); target.appendChild(cloudContainer); } GraphVizHandler.prototype.getColorForWeight = function (weight) { return getColorForWeight(weight); } GraphVizHandler.prototype.createSankeyChart = async function (target, title, linksData, nodesData,onClick = null) { const chartId = generateUUID(); const option = { title: { text: title, top: 'bottom', left: 'right' }, tooltip: { trigger: 'item', triggerOn: 'mousemove', formatter: function (params) { if (params.dataType === 'edge') { return params.data.source + ' → ' + params.data.target + ': ' + params.data.value + ''; } else { return params.name; } } }, series: { type: 'sankey', layout: 'none', data: nodesData, links: linksData, emphasis: { focus: 'adjacency', label: { show: true, color: '#000' } }, lineStyle: { color: 'gradient', curveness: 0.5 }, label: { //color: '#000' show: false } } }; const echart = new ECharts(target, option); // Pass full option this.activeCharts[chartId] = echart; echart.getInstance().on('click', function (params) { if (onClick && typeof onClick === 'function') { onClick(params); } if (params.dataType === 'node') { const clickedNode = params.name; const connectedNodes = new Set([clickedNode]); const connectedLinks = new Set(); linksData.forEach(link => { if (link.source === clickedNode || link.target === clickedNode) { connectedNodes.add(link.source); connectedNodes.add(link.target); connectedLinks.add(link.source + '->' + link.target); } }); const updatedNodes = nodesData.map(node => ({ ...node, label: { show: connectedNodes.has(node.name) }, itemStyle: { ...(node.itemStyle || {}), opacity: connectedNodes.has(node.name) ? 1 : 0.2 } })); const updatedLinks = linksData.map(link => ({ ...link, lineStyle: { ...(link.lineStyle || {}), opacity: connectedLinks.has(link.source + '->' + link.target) ? 1 : 0.1 } })); echart.getInstance().setOption({ series: [{ data: updatedNodes, links: updatedLinks }] }); } else { const resetNodes = nodesData.map(node => ({ ...node, label: { show: false }, // itemStyle: { // ...(node.itemStyle || {}), // opacity: 0.5 // } })); const resetLinks = linksData.map(link => ({ ...link, lineStyle: { color: 'gradient', curveness: 0.5 }, })); echart.getInstance().setOption({ series: [{ data: resetNodes, links: resetLinks }] }); } }); return echart; }; GraphVizHandler.prototype.createMiniBarChart = function ({ data = [], // Array of [label, value] title = '', // Chart title labelPrefix = '', // Optional prefix for title like "Topics for" labelHighlight = '', // The highlighted part (e.g., entity/topic name) primaryColor = '#5470C6', // Default bar color secondaryColor = '#91CC75', // Alternate bar color usePrimaryForEntity = false, // Toggle color logic barHeight = 10, // Height of bars in px maxBarWidth = 100, // Max bar width in px minLabelWidth = 70, // Width of label column in px fontSize = 10 // Font size for values } = {}) { // This function creates a simple mini bar chart in HTML which can be used in tooltips or small displays as hover actions. const maxVal = Math.max(...data.map(([_, v]) => v)) || 1; const barsHtml = data.map(([label, value]) => { const width = Math.round((value / maxVal) * maxBarWidth); return ( '
' ); }).join(''); const fullTitle = '' + labelPrefix + ''; return ( '
' ); } GraphVizHandler.prototype.createBarLineChart = async function ( target, title, config, tooltipFormatter, onClick = null ) { const chartId = generateUUID(); const { xData, seriesData, yLabel = 'Count' } = config; const option = { tooltip: { trigger: 'axis', enterable: true, backgroundColor: '#fff', borderColor: '#ccc', borderWidth: 1, textStyle: { color: '#000', fontSize: 12 }, formatter: tooltipFormatter }, title: { text: title, left: 'center' }, legend: { data: seriesData.map(s => s.name), top: 'auto' }, xAxis: { type: 'category', name: 'X', data: xData }, yAxis: { type: 'value', name: yLabel }, series: [] }; seriesData.forEach(s => { option.series.push({ name: s.name, type: 'bar', data: s.data, itemStyle: { color: s.color, opacity: 0.15 }, barGap: '-100%', z: 1 }); option.series.push({ name: s.name, type: 'line', data: s.data, symbol: 'circle', symbolSize: 10, lineStyle: { width: 3, color: s.color }, itemStyle: { color: s.color }, z: 2 }); }); const echart = new ECharts(target, option); this.activeCharts[chartId] = echart; if (onClick && typeof onClick === 'function') { echart.getInstance().on('click', onClick); } return echart; }; GraphVizHandler.prototype.createChordChart = async function ( target, title, data, tooltipFormatter = null, onClick = null ) { const chartId = generateUUID(); const hasGraphData = data.nodes && data.links && data.categories; const option = { title: { text: title, left: 'center' }, tooltip: { trigger: 'item', enterable: hasGraphData, formatter: hasGraphData ? tooltipFormatter : function (params) { if (params.dataType === 'edge') { return params.data.source + ' → ' + params.data.target + ': ' + params.data.value + ''; } return params.name; } }, legend: hasGraphData ? { data: data.categories.map(c => c.name), left: '10px', orient: 'vertical', position: 'right' } : undefined, series: hasGraphData ? [{ type: 'graph', layout: 'circular', circular: { rotateLabel: true }, data: data.nodes, links: data.links, categories: data.categories, roam: true, label: { rotate: 90, show: true }, itemStyle: { borderWidth: 1, borderColor: '#aaa' }, lineStyle: { opacity: 0.5, width: 2, curveness: 0.3 }, emphasis: { focus: 'adjacency', label: { show: true } } }] : { type: 'chord', data: data.nodes, links: data.links, emphasis: { focus: 'adjacency', label: { show: true, color: '#000' } }, itemStyle: { borderWidth: 1, borderColor: '#fff' } } }; const echart = new ECharts(target, option); this.activeCharts[chartId] = echart; echart.getInstance().on('click', function (params) { if (onClick && typeof onClick === 'function') { onClick(params); } }); return echart; }; GraphVizHandler.prototype.createHeatMap = async function ( target, title, matrix, labels, series_name= null, tooltipFormatter = null, onClick = null ) { const chartId = generateUUID(); const option = { title: { text: title, left: 'center' }, tooltip: { position: 'top', formatter: tooltipFormatter, }, grid: { left: '15%', bottom: '15%', containLabel: true }, xAxis: { type: 'category', data: labels, splitArea: { show: true }, axisLabel: { rotate: 45 } }, yAxis: { type: 'category', data: labels, splitArea: { show: true } }, visualMap: { min: 0, max: Math.max(...matrix.map(d => d[2])), calculable: true, orient: 'horizontal', left: 'center', bottom: '5%' }, series: [{ name: series_name || 'Heatmap', type: 'heatmap', data: matrix, roam: true, label: { show: false }, emphasis: { itemStyle: { shadowBlur: 10, shadowColor: 'rgba(0, 0, 0, 0.5)' } } }] }; const echart = new ECharts(target, option); this.activeCharts[chartId] = echart; echart.getInstance().on('click', function (params) { if (onClick && typeof onClick === 'function') { onClick(params); } }); return echart; }; GraphVizHandler.prototype.createNetworkGraph = async function ( target, title, nodes, links, tooltipFormatter = null, onClick = null ) { const chartId = generateUUID(); const option = { title: { text: '', left: 'center' }, tooltip: {}, xAxis: { show: false, min: 'dataMin', max: 'dataMax' }, yAxis: { show: false, min: 'dataMin', max: 'dataMax' }, animationDuration: 1500, animationEasingUpdate: 'quinticInOut', series: [{ type: 'graph', layout: 'force', draggable: true, force: { edgeLength: 5, repulsion: 10, gravity: 0.5 }, data: nodes, edges: links, roam: true, symbolSize: 10, label: { show: false }, emphasis: { focus: 'adjacency', lineStyle: { width: 10 } }, itemStyle: { borderColor: '#fff', borderWidth: 1 } }] }; const echart = new ECharts(target, option); this.activeCharts[chartId] = echart; echart.getInstance().on('click', function (params) { if (onClick && typeof onClick === 'function') { onClick(params); } }); return echart; }; return GraphVizHandler; }()); function getNewGraphVizHandler() { return new GraphVizHandler(); } function getColorForWeight(weight) { const r = Math.floor(255 * (1 - weight)); const g = Math.floor(200 * weight); const b = 0; return "rgba(" + r + ", " + g + ", " + b + ", 0.5)"; } window.graphVizHandler = getNewGraphVizHandler(); import {DrawflowJS} from '/js/visualization/drawflowjs.js'; var FlowVizHandler = (function () { FlowVizHandler.prototype.activeFlows = {}; function FlowVizHandler() { console.log('Created FlowVizHandler Handler.'); } FlowVizHandler.prototype.createFlowChart = async function (target, initialNode) { const flowId = generateUUID(); const flow = new DrawflowJS(target); flow.init(initialNode); this.activeFlows[flowId] = flow; activatePopovers(); } FlowVizHandler.prototype.createNewFromLinkableNode = async function (unique, target) { let container = undefined; if (target === undefined || target === '') { container = document.getElementById('full-flow-container'); $(container).parent('#flow-chart-modal').show(); container.innerHTML = ''; // reset the last chart } else { container = target; container.innerHTML = ''; // reset the last chart // Add a loader $(container).append(`
Loading
`); } $.ajax({ url: '/api/wiki/linkable/node', type: "POST", data: JSON.stringify({ unique: unique, }), contentType: "application/json", success: function (response) { const node = JSON.parse(response); window.flowVizHandler.createFlowChart(container, node); $(container).find('.full-loader').fadeOut(125); }, error: (xhr, status, error) => { showMessageModal("Unknown Error", "There was an unknown error loading the linkable node."); } }).always(() => { $(container).find('.full-loader').fadeOut(125); }); } return FlowVizHandler; }()); function getNewFlowVizHandler() { return new FlowVizHandler(); } window.flowVizHandler = getNewFlowVizHandler(); /** * This triggers whenever a button to */ $('body').on('click', '.open-linkable-node', function () { const unique = $(this).data('unique'); const target = $(this).data('target'); window.flowVizHandler.createNewFromLinkableNode(unique, target); })