diff --git a/.gitignore b/.gitignore index 202330f..8d3aca1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ node_modules/ .vscode yarn-error.log dst/ -dist/ \ No newline at end of file +dist/ +module/ \ No newline at end of file diff --git a/config/webpack.config.dev.js b/config/webpack.config.dev.js new file mode 100644 index 0000000..d8e2052 --- /dev/null +++ b/config/webpack.config.dev.js @@ -0,0 +1,25 @@ +// eslint-disable-next-line @typescript-eslint/no-var-requires +const path = require('path'); + +module.exports = { + entry: path.resolve(__dirname, '../src/index.ts'), + devtool: 'inline-source-map', + module: { + rules: [ + { + test: /\.tsx?$/, + use: 'ts-loader', + exclude: /node_modules/, + }, + ], + }, + resolve: { + extensions: [ '.ts', '.tsx', '.js' ], + }, + output: { + filename: 'facetTree.js', + path: path.resolve(__dirname, '../module'), + libraryTarget: "umd", + library: 'facetTree', + } +}; \ No newline at end of file diff --git a/src/data.ts b/data.ts similarity index 100% rename from src/data.ts rename to data.ts diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..3099a89 --- /dev/null +++ b/index.ts @@ -0,0 +1,69 @@ +import axios from 'axios'; + +import {drawTree} from './module/facetTree'; +import { data } from './data'; + +const svg = document.getElementById('mysvg'); + +async function clickFacet(facetId: number) { + + try { + const res = await axios.get('http://yotta.xjtushilei.com:8083/facet/getFacetNameAndParentFacetNameByFacetId', { + params: { + facetId, + } + }); + if ((res as any).data.code === 200) { + document.getElementById('facet').innerHTML = (res.data.data.parentFacetName ? res.data.data.parentFacetName + ' - ' : '') + res.data.data.facetName; + } else { + throw(res.data) + } + } catch (e) { + console.log(e); + document.getElementById('facet').innerHTML = ''; + } + + // empty list + const list = document.getElementById('list'); + const children = list.childNodes; + for (let i = 0; i < children.length; i++) { + list.removeChild(children[i]); + } + + const ul = document.createElement('ul'); + let assembleNumber = 0; + + try { + const res = await axios.get('http://yotta.xjtushilei.com:8083/assemble/getAssemblesByFacetId', { + params: { + facetId: facetId, + }, + }); + + if ((res as any).data.code === 200) { + const assembleList = res.data.data; + (assembleList as any).forEach(element => { + const li = document.createElement('li'); + li.className = 'assemble'; + if (element.type === 'video') { + const regex = new RegExp('https://.*mp4'); + li.innerHTML = `` + } else { + li.innerHTML = element.assembleContent; + } + ul.appendChild(li); + }); + assembleNumber = assembleList.length; + list.appendChild(ul); + document.getElementById('assembleNumber').innerHTML = assembleNumber.toString(); + } else { + throw ('api error'); + } + } catch (e) { + console.log(e); + document.getElementById('assembleNumber').innerHTML = ''; + } + +} + +drawTree(svg, data, clickFacet); \ No newline at end of file diff --git a/package.json b/package.json index 1516404..05407f5 100755 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ "test": "jest", "build": "rm -rf ./dst && tsc", "webpack": "webpack", - "dev": "rm -rf dist && npm run webpack -- --mode development", - "prod": "rm -rf dist && npm run webpack -- --mode production" + "dev": "rm -rf dist module && npm run webpack -- --mode development --config ./config/webpack.config.dev.js && npm run webpack -- --mode development", + "prod": "rm -rf dist module && npm run webpack -- --mode production --config ./config/webpack.config.dev.js && npm run webpack -- --mode production", + "pack": "rm -rf module && npm run webpack -- --mode production --config ./config/webpack.config.dev.js" } } diff --git a/src/draw-tree.ts b/src/draw-tree.ts index 5a8c58c..1995829 100644 --- a/src/draw-tree.ts +++ b/src/draw-tree.ts @@ -1,5 +1,5 @@ import * as d3 from 'd3'; -import { map, distinctUntilChanged, debounce, filter } from 'rxjs/operators'; +import { map, distinctUntilChanged, debounce, filter, skip } from 'rxjs/operators'; import { interval } from 'rxjs'; import { buildTree } from './facet-tree-ng'; @@ -7,12 +7,13 @@ import { drawFacetPieChart } from './facet-pie-chart'; import { drawFacetForceLayout } from './facet-force-layout'; import { globalState } from './state'; -function drawTree(svg, data, clickFacet): void { +export function drawTree(svg, data, clickFacet): void { const canvas = d3.select(svg); const treeData = buildTree(data, svg); globalState.pipe( - debounce(() => interval(1000)), + debounce(() => interval(200)), + skip(1), map(state => state.currentFacetId), distinctUntilChanged() ).subscribe(currentFacetId => { @@ -20,10 +21,12 @@ function drawTree(svg, data, clickFacet): void { }); globalState.pipe( - debounce(() => interval(1000)), + debounce(() => interval(200)), + skip(1), map(state => state.expandedFacetId), filter(expandedFacetId => { const [prev, curr] = expandedFacetId.split(','); + console.log(expandedFacetId); return prev !== curr; }), distinctUntilChanged() @@ -36,7 +39,7 @@ function drawTree(svg, data, clickFacet): void { expandedNodes[0].parentNode.removeChild(expandedNodes[0]); } // draw pie chart - drawFacetPieChart(treeData.facetChart.filter(x => x.facetId.toString() === prev)[0], svg, treeData, clickFacet); + drawFacetPieChart(treeData.facetChart.filter(x => x.facetId.toString() === prev)[0], svg); } if (curr !== '-2') { // delete pie chart @@ -45,7 +48,7 @@ function drawTree(svg, data, clickFacet): void { expandedNodes[0].parentNode.removeChild(expandedNodes[0]); } // draw force layout - drawFacetForceLayout(treeData.facetChart.filter(x => x.facetId.toString() === curr)[0], svg, clickFacet); + drawFacetForceLayout(treeData.facetChart.filter(x => x.facetId.toString() === curr)[0], svg); } }); @@ -86,11 +89,19 @@ function drawTree(svg, data, clickFacet): void { }) .attr('fill', d => d.color) .style('cursor', 'pointer') - .on('click', (d, i) => clickFacet(treeData.branches[i].facetId, treeData.branches[i].facetName)); + .on('click', (d, i) => { + const [prev, curr] = globalState.getValue().expandedFacetId.split(','); + globalState.next( + { + currentFacetId: treeData.branches[i].facetId, + expandedFacetId: curr + ',-2', + } + ) + }); // draw second layer facet treeData.facetChart.forEach(element => { // 饼图 - drawFacetPieChart(element, svg, treeData, clickFacet); + drawFacetPieChart(element, svg); // 力导向图 // drawFacetForceLayout(element, svg); }); diff --git a/src/facet-force-layout.ts b/src/facet-force-layout.ts index 2de265a..168a5fc 100644 --- a/src/facet-force-layout.ts +++ b/src/facet-force-layout.ts @@ -1,6 +1,8 @@ -import { FacetChartData } from './facet-tree-ng'; import * as d3 from 'd3'; +import { FacetChartData } from './facet-tree-ng'; +import { globalState } from './state'; + function calcFacetForceLayout(data: FacetChartData): {nodes: any[]; links: any[]} { const nodes = []; const links = []; @@ -39,7 +41,7 @@ function fixna(x: number): number { return 0; } -export function drawFacetForceLayout(data: FacetChartData, dom: HTMLElement, clickFacet: Function, fontSize = 12): void { +export function drawFacetForceLayout(data: FacetChartData, dom: HTMLElement, fontSize = 12): void { const container = d3.select(dom).append('g'); const { nodes, links } = calcFacetForceLayout(data); @@ -59,7 +61,13 @@ export function drawFacetForceLayout(data: FacetChartData, dom: HTMLElement, cli .attr('r', data.r / 2) .attr('fill', data.color) .style('cursor', 'pointer') - .on('click', d => clickFacet(d.facetId, data.facetName + '-' + d.facetName, data.facetId)); + .on('click', d => { + const [prev, next] = globalState.getValue().expandedFacetId.split(','); + globalState.next({ + currentFacetId: d.facetId, + expandedFacetId: next + ',' + data.facetId.toString(), + }); + }); const label = container.append('g') .selectAll('text') diff --git a/src/facet-pie-chart.ts b/src/facet-pie-chart.ts index 4e0090b..066d8da 100644 --- a/src/facet-pie-chart.ts +++ b/src/facet-pie-chart.ts @@ -1,7 +1,9 @@ -import { FacetChartData, FacetData, Tree } from './facet-tree-ng'; import * as d3 from 'd3'; -export function drawFacetPieChart(data: FacetChartData, dom: HTMLElement, treeData: Tree, clickFacet: Function, fontSize = 12): void { +import { FacetChartData, FacetData, Tree } from './facet-tree-ng'; +import { globalState } from './state'; + +export function drawFacetPieChart(data: FacetChartData, dom: HTMLElement, fontSize = 12): void { const canvas = d3.select(dom); canvas.append('g') .attr('class', data.facetId) @@ -18,10 +20,11 @@ export function drawFacetPieChart(data: FacetChartData, dom: HTMLElement, treeDa .attr("stroke-width", data.r / 10) .style('cursor', 'pointer') .on('click', d => { - let facetName = ' - ' + (d.data as any).facetName; - const firstFacetId = (d.data as any).parentFacetId; - facetName = ' ' + treeData.branches.filter(branch => branch.facetId === firstFacetId)[0].facetName + facetName; - clickFacet((d.data as any).facetId, facetName, data.facetId); + const [prev, curr] = globalState.getValue().expandedFacetId.split(','); + globalState.next({ + currentFacetId: (d.data as any).facetId, + expandedFacetId: curr + ',' + data.facetId.toString(), + }); }); const num = data.childrenNumber; const angle = Math.PI / num; diff --git a/src/index.ts b/src/index.ts index cef755c..32ac71e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,64 +1,4 @@ -import * as d3 from 'd3'; -import axios from 'axios'; - - -import { buildTree, FacetData } from './facet-tree-ng'; -import { data } from './data'; -import { drawFacetPieChart } from './facet-pie-chart'; -import { drawFacetForceLayout } from './facet-force-layout'; - -const svg = document.getElementById('mysvg'); - -let currentFacetId = -1; - -async function clickFacet(facetId: number, facetName: string, parentFacetId = -2) { - // return when facetId not change - if (currentFacetId === facetId) return; - - // save facetId - currentFacetId = facetId; - - // empty list - const list = document.getElementById('list'); - const children = list.childNodes; - for (let i = 0; i < children.length; i++) { - list.removeChild(children[i]); - } - - const ul = document.createElement('ul'); - let assembleNumber = 0; - - try { - const res = await axios.get('http://yotta.xjtushilei.com:8083/assemble/getAssemblesByFacetId', { - params: { - facetId: facetId, - }, - }); - - if ((res as any).data.code === 200) { - const assembleList = res.data.data; - (assembleList as any).forEach(element => { - const li = document.createElement('li'); - li.className = 'assemble'; - if (element.type === 'video') { - const regex = new RegExp('https://.*mp4'); - li.innerHTML = `` - } else { - li.innerHTML = element.assembleContent; - } - ul.appendChild(li); - }); - assembleNumber = assembleList.length; - } else { - throw ('api error'); - } - } catch (e) { - console.log(e); - } - // whether current facet has changed or not - if (currentFacetId === facetId) { - list.appendChild(ul); - document.getElementById('facet').innerHTML = facetName; - document.getElementById('assembleNumber').innerHTML = assembleNumber.toString(); - } -} \ No newline at end of file +export * from './draw-tree'; +export * from './facet-tree-ng'; +export * from './facet-force-layout'; +export * from './facet-pie-chart'; diff --git a/tsconfig.json b/tsconfig.json index 7cd71bd..0d2d557 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,6 @@ "target": "es5", "types": ["lodash", "d3", "jest"], "sourceMap": true, - "rootDir": "src", "outDir": "dst", "lib": [ "es5", @@ -15,7 +14,7 @@ ] }, "include": [ - "src/*" + "src/*", "data.ts" ], "exclude": [ "node_modules" diff --git a/webpack.config.js b/webpack.config.js index a64b9a1..bed6461 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -2,7 +2,7 @@ const path = require('path'); module.exports = { - entry: path.resolve(__dirname, './src/index.ts'), + entry: path.resolve(__dirname, 'index.ts'), devtool: 'inline-source-map', module: { rules: [