Changeset 3334722
- Timestamp:
- 07/27/2025 07:19:08 AM (8 months ago)
- Location:
- plot-beam/trunk
- Files:
-
- 20 edited
-
package.json (modified) (2 diffs)
-
src/edit.js (modified) (11 diffs)
-
src/index.js (modified) (5 diffs)
-
src/svelte/App.svelte (modified) (1 diff)
-
src/svelte/Chart.svelte (modified) (2 diffs)
-
src/svelte/Entry.svelte (modified) (2 diffs)
-
src/svelte/appConfig/types.ts (modified) (2 diffs)
-
src/svelte/component/bar/AxisX.svelte (modified) (3 diffs)
-
src/svelte/component/bar/AxisY.svelte (modified) (1 diff)
-
src/svelte/component/bar/Bar.svelte (modified) (4 diffs)
-
src/svelte/component/bar/Tooltip.svelte (modified) (3 diffs)
-
src/svelte/component/gauge/Gauge.svelte (modified) (4 diffs)
-
src/svelte/component/lineChart/LineChart.svelte (modified) (5 diffs)
-
src/svelte/component/lineChart/Tooltip.svelte (modified) (2 diffs)
-
src/svelte/component/scatterPlot/AxisX.svelte (modified) (2 diffs)
-
src/svelte/component/scatterPlot/ScatterPlot.svelte (modified) (3 diffs)
-
src/svelte/component/scatterPlot/Tooltip.svelte (modified) (4 diffs)
-
src/svelte/lib/bar/getBarsWidth.ts (modified) (2 diffs)
-
src/svelte/lib/getBaseRange.test.ts (modified) (2 diffs)
-
src/svelte/lib/getDisplayValue.ts (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
plot-beam/trunk/package.json
r3009739 r3334722 22 22 "test": "vitest" 23 23 }, 24 "de vDependencies": {24 "dependencies": { 25 25 "@sveltejs/vite-plugin-svelte": "^2.4.2", 26 "@tsconfig/svelte": "^5.0.0", 27 "@types/d3": "^7.4.3", 28 "@wordpress/scripts": "^26.9.0", 29 "d3": "^7.8.5", 30 "npm-run-all": "^4.1.5", 31 "vite": "^4.4.5", 32 "vitest": "^0.34.3", 26 33 "@testing-library/jest-dom": "^6.1.2", 27 34 "@testing-library/svelte": "^4.0.3", 28 "@tsconfig/svelte": "^5.0.0",29 "@types/d3": "^7.4.0",30 "@wordpress/scripts": "^26.11.0",31 35 "jsdom": "^22.1.0", 32 36 "svelte": "^4.0.5", … … 34 38 "tslib": "^2.6.0", 35 39 "typescript": "^5.0.2", 36 "vite": "^4.4.5", 37 "vitest": "^0.34.3" 38 }, 39 "dependencies": { 40 "@sveltestack/svelte-query": "^1.6.0", 41 "d3": "^7.8.5", 42 "npm-run-all": "^4.1.5", 43 "vitest": "^0.34.3" 40 "uuid": "^11.1.0" 44 41 } 45 42 } -
plot-beam/trunk/src/edit.js
r3011616 r3334722 4 4 SelectControl, 5 5 Button, 6 } from "@wordpress/components";6 } from '@wordpress/components'; 7 7 8 8 /** … … 11 11 * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-i18n/ 12 12 */ 13 import { __ } from "@wordpress/i18n";13 import { __ } from '@wordpress/i18n'; 14 14 15 15 /** … … 19 19 * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops 20 20 */ 21 import { useBlockProps } from "@wordpress/block-editor";21 import { useBlockProps } from '@wordpress/block-editor'; 22 22 23 23 /** … … 27 27 * @see https://www.npmjs.com/package/@wordpress/scripts#using-css 28 28 */ 29 import "./editor.scss";29 import './editor.scss'; 30 30 31 31 /** … … 37 37 * @return {WPElement} Element to render. 38 38 */ 39 export default function Edit( props) {39 export default function Edit( props ) { 40 40 const blockProps = useBlockProps(); 41 const dataTypeFn = (value) => { 42 props.setAttributes({ dataType: value }); 43 switch (value) { 44 case "userData": 45 props.setAttributes({ appID: "" }); 46 props.setAttributes({ objectID: "" }); 47 props.setAttributes({ 48 description: "This contains organisational data", 49 }); 50 break; 51 case "bar": 52 props.setAttributes({ appID: "da8c91fe-88fd-45ef-b573-596621f7ec6f" }); 53 props.setAttributes({ objectID: "aBGkzz" }); 54 props.setAttributes({ objectTitle: "Example bar plot" }); 55 props.setAttributes({ description: "This contains test data" }); 56 break; 57 case "line": 58 props.setAttributes({ appID: "da8c91fe-88fd-45ef-b573-596621f7ec6f" }); 59 props.setAttributes({ 60 objectID: "ec48858d-b158-432d-b60c-da7344d8bc9a", 61 }); 62 props.setAttributes({ objectTitle: "Example line plot" }); 63 props.setAttributes({ description: "This contains test data" }); 64 break; 65 case "scatterplot": 66 props.setAttributes({ appID: "da8c91fe-88fd-45ef-b573-596621f7ec6f" }); 67 props.setAttributes({ 68 objectID: "e3ed1aa7-a066-4358-a64e-0beb1c433317", 69 }); 70 props.setAttributes({ objectTitle: "Example scatterplot" }); 71 props.setAttributes({ description: "This contains test data" }); 72 break; 73 case "gauge": 74 props.setAttributes({ appID: "da8c91fe-88fd-45ef-b573-596621f7ec6f" }); 75 props.setAttributes({ 76 objectID: "576c5fc2-e038-4c90-b682-4e17b2fd846e", 77 }); 78 props.setAttributes({ objectTitle: "Example gauge plot " }); 79 props.setAttributes({ description: "This contains test data" }); 41 const dataTypeFn = ( value ) => { 42 props.setAttributes( { dataType: value } ); 43 switch ( value ) { 44 case 'userData': 45 props.setAttributes( { appID: '' } ); 46 props.setAttributes( { objectID: '' } ); 47 props.setAttributes( { 48 description: 'This contains organisational data', 49 } ); 50 break; 51 case 'bar': 52 props.setAttributes( { 53 appID: 'da8c91fe-88fd-45ef-b573-596621f7ec6f', 54 } ); 55 props.setAttributes( { objectID: 'aBGkzz' } ); 56 props.setAttributes( { objectTitle: 'Example bar plot' } ); 57 props.setAttributes( { 58 description: 'This contains test data', 59 } ); 60 break; 61 case 'line': 62 props.setAttributes( { 63 appID: 'da8c91fe-88fd-45ef-b573-596621f7ec6f', 64 } ); 65 props.setAttributes( { 66 objectID: 'ec48858d-b158-432d-b60c-da7344d8bc9a', 67 } ); 68 props.setAttributes( { objectTitle: 'Example line plot' } ); 69 props.setAttributes( { 70 description: 'This contains test data', 71 } ); 72 break; 73 case 'scatterplot': 74 props.setAttributes( { 75 appID: 'da8c91fe-88fd-45ef-b573-596621f7ec6f', 76 } ); 77 props.setAttributes( { 78 objectID: 'e3ed1aa7-a066-4358-a64e-0beb1c433317', 79 } ); 80 props.setAttributes( { objectTitle: 'Example scatterplot' } ); 81 props.setAttributes( { 82 description: 'This contains test data', 83 } ); 84 break; 85 case 'gauge': 86 props.setAttributes( { 87 appID: 'da8c91fe-88fd-45ef-b573-596621f7ec6f', 88 } ); 89 props.setAttributes( { 90 objectID: '576c5fc2-e038-4c90-b682-4e17b2fd846e', 91 } ); 92 props.setAttributes( { objectTitle: 'Example gauge plot ' } ); 93 props.setAttributes( { 94 description: 'This contains test data', 95 } ); 80 96 break; 81 97 default: 82 props.setAttributes( { appID: "" });83 props.setAttributes( { objectID: "" });84 props.setAttributes( { description: "" });98 props.setAttributes( { appID: '' } ); 99 props.setAttributes( { objectID: '' } ); 100 props.setAttributes( { description: '' } ); 85 101 break; 86 102 } 87 103 }; 88 const openInNewTab = ( url) => {89 window.open( url, "_blank", "noopener,noreferrer");104 const openInNewTab = ( url ) => { 105 window.open( url, '_blank', 'noopener,noreferrer' ); 90 106 }; 91 107 92 108 return ( 93 <div className="wp-block-create-block-plot-beam" { ...blockProps}>94 { __(109 <div className="wp-block-create-block-plot-beam" { ...blockProps }> 110 { __( 95 111 <div className="admin-form"> 96 112 <SelectControl 97 113 className="select first" 98 114 label="Select data type" 99 value={ props.attributes.dataType}115 value={ props.attributes.dataType } 100 116 required 101 options={[ 102 { label: "Select Options", value: null }, 103 { label: "Your Organisation Data", value: "userData" }, 104 { label: "Example data-Bar chart", value: "bar" }, 105 { label: "Example data-Line chart", value: "line" }, 106 { label: "Example data-Scatterplot chart", value: "scatterplot" }, 107 { label: "Example data-Gauge chart", value: "gauge" }, 108 ]} 109 onChange={(value) => dataTypeFn(value)} 117 options={ [ 118 { label: 'Select Options', value: null }, 119 { 120 label: 'Your Organisation Data', 121 value: 'userData', 122 }, 123 { label: 'Example data-Bar chart', value: 'bar' }, 124 { label: 'Example data-Line chart', value: 'line' }, 125 { 126 label: 'Example data-Scatterplot chart', 127 value: 'scatterplot', 128 }, 129 { 130 label: 'Example data-Gauge chart', 131 value: 'gauge', 132 }, 133 ] } 134 onChange={ ( value ) => dataTypeFn( value ) } 110 135 /> 111 { props.attributes.dataType === "userData"&& (136 { props.attributes.dataType === 'userData' && ( 112 137 <div className="button-group"> 113 138 <Button 114 139 className="button" 115 onClick={() => 116 openInNewTab("https://plot-beam.azurewebsites.net/register") 140 onClick={ () => 141 openInNewTab( 142 'https://plot-beam.azurewebsites.net/register' 143 ) 117 144 } 118 145 > 119 146 Create a new Plot Beam page 120 147 <br /> 121 Connect my QlikSense data and create new visualisation 148 Connect my QlikSense data and create new 149 visualisation 122 150 </Button> 123 151 <Button 124 152 className="button" 125 onClick={() => 126 openInNewTab("https://plot-beam.azurewebsites.net/return") 153 onClick={ () => 154 openInNewTab( 155 'https://plot-beam.azurewebsites.net/return' 156 ) 127 157 } 128 158 > 129 159 Go to my Plot Beam page 130 <br />I have already created a Plot Beam site for my131 organisation160 <br />I have already created a Plot Beam site 161 for my organisation 132 162 </Button> 133 163 </div> 134 ) }164 ) } 135 165 <TextControl 136 166 className="form-text" … … 138 168 type="text" 139 169 help="Short title for the chart, 5 words max" 140 value={props.attributes.objectTitle} 141 onChange={(value) => props.setAttributes({ objectTitle: value })} 170 value={ props.attributes.objectTitle } 171 onChange={ ( value ) => 172 props.setAttributes( { objectTitle: value } ) 173 } 142 174 /> 143 { props.attributes.dataType === "userData"? (175 { props.attributes.dataType === 'userData' ? ( 144 176 <TextControl 145 177 className="form-text" … … 147 179 type="text" 148 180 help="Object Slug Example:0gnriLVVas7CxY0Q-cZ77OKLLeEwNoumk/aBGkzz " 149 value={props.attributes.objectSlug} 150 onChange={(value) => props.setAttributes({ objectSlug: value })} 181 value={ props.attributes.objectSlug } 182 onChange={ ( value ) => 183 props.setAttributes( { objectSlug: value } ) 184 } 151 185 /> 152 186 ) : ( … … 157 191 type="text" 158 192 help="Demo App ID: da8c91fe-88fd-45ef-b573-596621f7ec6f" 159 value={props.attributes.appID} 160 onChange={(value) => props.setAttributes({ appID: value })} 193 value={ props.attributes.appID } 194 onChange={ ( value ) => 195 props.setAttributes( { appID: value } ) 196 } 161 197 /> 162 198 <TextControl … … 165 201 type="text" 166 202 help="Demo Object ID: aBGkzz" 167 value={props.attributes.objectID} 168 onChange={(value) => props.setAttributes({ objectID: value })} 203 value={ props.attributes.objectID } 204 onChange={ ( value ) => 205 props.setAttributes( { objectID: value } ) 206 } 169 207 /> 170 208 </> 171 ) }209 ) } 172 210 <TextControl 173 211 className="form-text" … … 175 213 type="text" 176 214 help="Short description for the chart, 100 words max" 177 value={props.attributes.description} 178 onChange={(value) => props.setAttributes({ description: value })} 215 value={ props.attributes.description } 216 onChange={ ( value ) => 217 props.setAttributes( { description: value } ) 218 } 179 219 /> 180 220 <Text className="support"> 181 For assistance, please visit our Support Portal at{ " "}221 For assistance, please visit our Support Portal at{ ' ' } 182 222 <a 183 223 className="notitia" … … 187 227 </a> 188 228 </Text> 189 </div> ,190 ) }229 </div> 230 ) } 191 231 </div> 192 232 ); -
plot-beam/trunk/src/index.js
r3009739 r3334722 4 4 * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/ 5 5 */ 6 import { registerBlockType } from "@wordpress/blocks";6 import { registerBlockType } from '@wordpress/blocks'; 7 7 8 8 /** … … 13 13 * @see https://www.npmjs.com/package/@wordpress/scripts#using-css 14 14 */ 15 import "./style.scss";15 import './style.scss'; 16 16 17 17 /** 18 18 * Internal dependencies 19 19 */ 20 import Edit from "./edit.js";21 import save from "./save.js";22 import metadata from "./block.json";20 import Edit from './edit.js'; 21 import save from './save.js'; 22 import metadata from './block.json'; 23 23 24 24 /** … … 27 27 * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/ 28 28 */ 29 registerBlockType( metadata.name, {29 registerBlockType( metadata.name, { 30 30 icon: ( 31 31 <svg … … 70 70 ), 71 71 attributes: { 72 appID: { type: "string"},73 objectID: { type: "string"},74 objectTitle: { type: "string"},75 description: { type: "string"},76 dataType: { type: "string"},77 objectSlug: { type: "string"},72 appID: { type: 'string' }, 73 objectID: { type: 'string' }, 74 objectTitle: { type: 'string' }, 75 description: { type: 'string' }, 76 dataType: { type: 'string' }, 77 objectSlug: { type: 'string' }, 78 78 }, 79 79 80 80 example: { 81 81 attributes: { 82 objectTitle: "Sales",83 appID: "0d40467d-e362-4d74-b445-4166a1b32cc9",84 objectID: "MkcvQD",85 description: "A chart to show case sales in detail",86 dataType: "userData",87 objectSlug: "0gnriLVVas7CxY0Q-cZ77OKLLeEwNoumk/aBGkzz",82 objectTitle: 'Sales', 83 appID: '0d40467d-e362-4d74-b445-4166a1b32cc9', 84 objectID: 'MkcvQD', 85 description: 'A chart to show case sales in detail', 86 dataType: 'userData', 87 objectSlug: '0gnriLVVas7CxY0Q-cZ77OKLLeEwNoumk/aBGkzz', 88 88 }, 89 89 }, … … 97 97 */ 98 98 save, 99 } );99 } ); -
plot-beam/trunk/src/svelte/App.svelte
r3009739 r3334722 1 1 <script lang="ts"> 2 import { QueryClient, QueryClientProvider } from "@sveltestack/svelte-query";3 2 import Entry from "./Entry.svelte" 4 3 import type{AppProp} from './appConfig/types'; 5 4 export let props: AppProp; 6 7 const queryClient = new QueryClient({8 defaultOptions: {9 queries: {10 cacheTime: 1 * (60 * 1000), // 5 mins11 retry: 1,12 refetchOnWindowFocus: "always",13 refetchInterval: 5 * 60 * 1000,14 },15 },16 });17 5 </script> 18 6 19 <QueryClientProvider client={queryClient}>20 7 <Entry {props} /> 21 </QueryClientProvider> 8 22 9 23 10 <style> -
plot-beam/trunk/src/svelte/Chart.svelte
r3073590 r3334722 6 6 import ScatterPlot from './component/scatterPlot/ScatterPlot.svelte'; 7 7 import LineChart from './component/lineChart/LineChart.svelte'; 8 import { getGaugeProps } from './lib/gauge/getGaugePorps'; 9 import getLineProps from './lib/line/getLineProps'; 10 import getBarProps from './lib/bar/getBarProps'; 11 import getScatterPlotProps from './lib/scatterPlot/getScatterPlotProps'; 12 import { isGauge } from './lib/chartDataTypeCheck'; 13 // export let data: QlikChartDataType<GaugeChartDataType | LineChartDataType | ScatterplotChartDataType | BarChartDataType>; 14 export let data: ChartData; 15 16 const styleChoice ="notitia" 17 const decimal = 0 18 const label = "percentage" 19 const valueOptions = "millions" 8 import { isBar, isGauge, isLine, isScatterPlot } from './lib/chartDataTypeCheck'; 9 export let chartID; 10 export let data; 20 11 21 12 const chartPool = ['gauge', 'scatterplot', 'barchart', 'linechart'] … … 27 18 {#if isInPool && data} 28 19 {#if isGauge(data) } 29 {#await getGaugeProps(data, styleChoice, label, valueOptions, decimal) then gaugeProps}30 20 <Gauge 31 valueSlices={gaugeProps.valueSlices} 32 segmentSlices={gaugeProps.segmentSlices} 33 valueColors={gaugeProps.valueColors} 34 displayMarks={gaugeProps.displayMarks} 35 displayValue ={gaugeProps.displayValue} 36 segmentColors={gaugeProps.segmentColors} 37 /> 38 {/await} 21 {...data} 22 /> 39 23 {/if} 40 {#if data.visType === "barchart"} 41 {#await getBarProps(data, styleChoice, label, valueOptions, decimal) then barProps} 24 {#if isBar(data)} 42 25 <Bar 43 nodesData = {barProps.nodesData} 44 group = {barProps.group} 45 subGroup={barProps.subGroup} 46 groupLabel={barProps.groupLabel} 26 {...data} 27 {chartID} 47 28 /> 48 {/await}49 29 {/if} 50 30 51 {#if data.visType === "scatterplot"} 52 {#await getScatterPlotProps(data, styleChoice, label, valueOptions, decimal) then scatterPlotProps} 31 {#if isScatterPlot(data)} 53 32 <ScatterPlot 54 xMeasure = {scatterPlotProps.xMeasure} 55 yMeasure = {scatterPlotProps.yMeasure} 56 dimension = {scatterPlotProps.dimension} 57 nodesData = {scatterPlotProps.nodesData} 58 nodeLabel = {scatterPlotProps.nodeLabel} 33 {...data} 34 {chartID} 59 35 /> 60 {/await}61 36 {/if} 62 37 63 {#if data.visType === "linechart"} 64 {#await getLineProps(data, styleChoice, label, valueOptions, decimal) then lineProps} 65 <LineChart 66 nodesData={lineProps.nodesData} 67 xTicks={lineProps.xTicks} 68 lines={lineProps.lines} 69 measurements={lineProps.measurements} 70 dimensions={lineProps.dimensions} 71 /> 72 {/await} 38 {#if isLine(data)} 39 <LineChart 40 {...data} 41 {chartID} 42 /> 73 43 {/if} 74 44 {:else} -
plot-beam/trunk/src/svelte/Entry.svelte
r3073590 r3334722 1 1 <script lang="ts"> 2 import type {AppProp , BarChartDataType, ChartData, LineChartDataType, QlikChartDataType, ScatterplotChartDataType} from './appConfig/types';2 import type {AppProp} from './appConfig/types'; 3 3 export let props: AppProp; 4 import type { UseQueryStoreResult } from "@sveltestack/svelte-query";5 4 import Chart from './Chart.svelte'; 6 5 import BrandIcon from './component/BrandIcon.svelte'; 7 import type {AxiosError} from 'axios'; 8 import { getPBChartData } from './lib/getPbChartData'; 9 import { getTestChartData } from './lib/getTestChartData'; 10 6 import { getChartData } from './lib/getChartData'; 7 import { v4 as uuidv4 } from 'uuid'; 8 const chartID=uuidv4() 11 9 const { 12 appID,13 objectID,14 10 description, 15 11 objectTitle, 16 dataType,17 objectSlug18 12 } = props; 19 20 let result: UseQueryStoreResult<ChartData, AxiosError>;21 //getting object data from Qlik22 $: result = dataType==="userData"? getPBChartData(objectSlug): getTestChartData(appID, objectID);23 24 13 </script> 25 14 … … 31 20 </div> 32 21 <div class="card-body"> 33 {#if $result.isLoading}34 <div class="card-chart">22 {#await getChartData(props)} 23 <div class="card-chart"> 35 24 <div class="custom-loader" /> 36 25 </div> 37 {:else if $result.error}38 <div class="card-chart card-error">39 Something went wrong: {$result.error.message}26 {:then result} 27 <div class="card-chart-title"> 28 {props.objectTitle} 40 29 </div> 41 {:else if $result.data} 42 <div class="card-chart-title"> 43 {$result.data.measurements[0]} 44 </div> 45 <div class="card-chart"> 46 <Chart data={$result.data} {props} /> 30 <div class="card-chart" id=""> 31 <Chart data={result.data} {chartID}/> 47 32 </div> 48 33 {#if description} 49 34 <div class="card-description">{description}</div> 50 35 {/if} 51 {/if} 36 {:catch error} 37 <div class="card-chart card-error"> 38 Something went wrong: {error} 39 </div> 40 {/await} 52 41 </div> 53 42 </div> -
plot-beam/trunk/src/svelte/appConfig/types.ts
r3073590 r3334722 2 2 3 3 type AppProp = { 4 appID: string; 5 objectID: string; 6 description: string; 7 objectTitle: string; 8 dataType: string; 9 objectSlug: string; 10 // styleChoice: StyleOptions; 11 // label: LabelOptions; 12 // valueOptions: ValueOptions; 13 // decimal: number; 14 }; 15 16 type QlikChartDataType<ChartData> = { 17 data: ChartData; 18 }; 19 20 type GaugeChartDataType = QlikChartDataType<{ 21 visType: string; 22 dimensions: string[]; 23 measurements: string[]; 24 measureAxis: MeasureAxis; 25 segmentInfo: SegmentInfo; 26 exactData: string[]; 27 }>; 28 29 type LineChartDataType = QlikChartDataType<{ 30 visType: string; 31 dimensions: string[]; 32 measurements: string[]; 33 exactData: ExactData<TypeOneExactData[]> | ExactData<TypeTwoExactData[]>; 34 }>; 35 36 type BarChartDataType = QlikChartDataType<{ 37 visType: string; 38 dimensions: string[]; 39 measurements: string[]; 40 exactData: ExactData<TypeOneExactData[]> | ExactData<TypeTwoExactData[]>; 41 }>; 42 43 type ScatterplotChartDataType = QlikChartDataType<{ 44 visType: string; 45 dimensions: string[]; 46 measurements: string[]; 47 exactData: [string, number, number][]; 48 }>; 49 50 type SubNode = { 51 qText: string; 52 qNum: number; 53 qSubNodes: { 54 qText: string; 55 qValue: number; 56 }[]; 57 }; 58 type Nodes = { 59 qSubNodes: SubNode[]; 60 qText: string; 61 }; 62 type QData = { 63 qElemNumber: number; 64 qText: string; 65 qNum: number; 66 qSubNodes: Nodes[]; 67 }; 68 type TypeOneExactData = { 69 qData: QData[]; 70 }; 71 type TypeTwoExactData = [string, ...[number]]; 72 type ExactData<T extends TypeOneExactData[] | TypeTwoExactData[]> = T; 73 // type ChartData< 74 // T extends 75 // | BarChartDataType 76 // | LineChartDataType 77 // | ScatterplotChartDataType 78 // | GaugeChartDataType, 79 // > = T["data"]; 80 type MeasureAxis = { 81 min: number; 82 max: number; 83 }; 84 type Limits = { 85 value: number; 86 gradient: boolean; 87 }; 88 89 type PaletteColors = { 90 color: string; 91 index: number; 92 }; 93 type SegmentInfo = { 94 paletteColors: PaletteColors[]; 95 limits: Limits[]; 96 }; 97 98 type ChartData = { 99 visType: string; 100 dimensions: string[]; 101 measurements: string[]; 102 measureAxis?: MeasureAxis; 103 segmentInfo?: SegmentInfo; 104 exactData: any[]; 4 appID: string; 5 objectID: string; 6 description: string; 7 objectTitle: string; 8 dataType: string; 9 objectSlug: string; 10 // styleChoice: StyleOptions; 11 // label: LabelOptions; 12 // valueOptions: ValueOptions; 13 // decimal: number; 105 14 }; 106 15 107 16 type GaugeProps = { 108 segmentColors: string[]; 109 segmentSlices: number[]; 110 displayMarks: string[]; 111 displayValue: string; 112 valueSlices: number[]; 113 valueColors: string[]; 114 }; 115 116 type DonutProps = { 117 data: number; 118 index: number; 119 value: number; 120 startAngle: number; 121 endAngle: number; 122 padAngle: number; 17 segmentColors: string[]; 18 segmentSlices: number[]; 19 segmentMarks: string[]; 20 value: string; 21 valueSlices: number[]; 22 valueColors: string[]; 123 23 }; 124 24 125 25 type ScatterPlotProps = { 126 xMeasure: string;127 yMeasure: string;128 dimension: string;129 nodesData: number[][];130 nodeLabel: string[];26 xMeasure: string; 27 yMeasure: string; 28 dimension: string; 29 nodesData: number[][]; 30 nodeLabel: string[]; 131 31 }; 132 32 133 33 type BarProps = { 134 group: string[];135 subGroup: string[];136 groupLabel: string;137 nodesData: number[][];34 group: string[]; 35 subGroup: string[]; 36 groupLabel: string; 37 nodesData: number[][]; 138 38 }; 139 39 140 40 type LineProps = { 141 nodesData: number[][];142 lines: string[];143 xTicks: string[];144 measurements: string[];145 dimensions: string[];41 nodesData: number[][]; 42 lines: string[]; 43 xTicks: string[]; 44 measurement: string[]; 45 dimensions: string[]; 146 46 }; 147 47 148 type ChartProps = BarProps | ScatterPlotProps | GaugeProps | LineProps;149 48 type StyleOptions = "qlik" | "notitia"; 150 49 type LabelOptions = "value" | "percentage"; … … 152 51 153 52 export type { 154 AppProp, 155 BarChartDataType, 156 GaugeChartDataType, 157 ScatterplotChartDataType, 158 ScatterPlotProps, 159 BarProps, 160 GaugeProps, 161 DonutProps, 162 StyleOptions, 163 LabelOptions, 164 ValueOptions, 165 SegmentInfo, 166 ChartProps, 167 LineProps, 168 MeasureAxis, 169 LineChartDataType, 170 ExactData, 171 TypeOneExactData, 172 TypeTwoExactData, 173 QlikChartDataType, 174 ChartData, 53 AppProp, 54 ScatterPlotProps, 55 BarProps, 56 GaugeProps, 57 StyleOptions, 58 LabelOptions, 59 ValueOptions, 60 LineProps, 175 61 }; -
plot-beam/trunk/src/svelte/component/bar/AxisX.svelte
r3009739 r3334722 1 1 <script lang="ts"> 2 import { height, width, margin,innerHeight, innerWidth} from "../../lib/canvasSetup";2 import { innerHeight, innerWidth} from "../../lib/canvasSetup"; 3 3 export let xScale: any; 4 4 export let nodesData: number[][]; 5 5 export let bandwidth: number; 6 6 export let barsWidth:number; 7 export let yScale: any;8 7 export let groupLabel: string; 9 8 export let group: string[]; … … 18 17 <text class="xTicks" y={innerHeight} x={xScale(group[index])} stroke="grey" 19 18 dx={bandwidth/2} dy={15} text-anchor="middle">{group[index]}</text> 20 <!-- {#if yScale(row[1]) < innerHeight/2}21 <text class="subGroup" y={innerHeight/2} x={xScale(row[0])} stroke="grey"22 dx={bandwidth/2} dy={-5} text-anchor="middle">{row[0]}</text>23 {:else} -->24 <!-- <text class="subGroup" y={yScale(row[1])} x={xScale(row[0])} stroke="grey"25 dx={bandwidth/2} dy={-5} text-anchor="end">{row[0]}</text> -->26 <!-- {/if} -->27 19 {/each} 28 20 </g> … … 30 22 .xTicks { 31 23 font-size: 10px; 32 } 33 .subGroup { 34 writing-mode: vertical-rl; 35 text-orientation: mixed; 36 } 24 } 37 25 </style> -
plot-beam/trunk/src/svelte/component/bar/AxisY.svelte
r3009739 r3334722 1 1 <script lang="ts"> 2 import * as d3 from "d3" 3 import {margin, height, width, innerHeight, innerWidth} from '../../lib/canvasSetup' 2 import { innerHeight} from '../../lib/canvasSetup' 4 3 export let yTicks: number[]; 5 4 export let yScale: any; -
plot-beam/trunk/src/svelte/component/bar/Bar.svelte
r3009739 r3334722 9 9 import AxisX from "./AxisX.svelte"; 10 10 import AxisY from "./AxisY.svelte"; 11 import { getExtendedRange } from "../../lib/getExtendedRange";12 import getBaseRange from "../../lib/getBaseRange";13 11 import getBarsWidth from "../../lib/bar/getBarsWidth"; 14 12 import getTicks from "../../lib/getTicks"; 15 13 import Tooltip from "./Tooltip.svelte"; 16 export let nodesData: number[][]; 17 export let groupLabel: string; 18 export let group: string[]; 19 export let subGroup: string[] 20 let width: number; 14 15 export let data; 16 export let measure; 17 export let dimensions; 18 export let chartID: string; 19 20 let width: number; 21 21 22 const colors = ['#9ADDC2', '#37CC90', '#29996C', '#154D36', '#002415', 22 23 '#BECDF7','#185DF2', '#1245B3', '#0B2C73', '#C4C4C4'] 23 $: xMeasureData = group24 $: yBaseRange = getBaseRange(nodesData)25 $: yDomain = getExtendedRange(yBaseRange);26 $: barsWidth = getBarsWidth(group, subGroup, nodesData, innerWidth);24 $: subGroup = dimensions.subgroupTicks; 25 $: group = dimensions.groupTicks; 26 $: groupLabel = dimensions.groupTitle; 27 $: yTicks = measure.ticks; 27 28 29 $: nodesData = data.map((node: [string, number[]]) => node[1]); 30 $: yDomain = [measure.ticks[0], measure.ticks[measure.ticks.length - 1]]; 31 32 $: barsWidth = getBarsWidth(group, subGroup , nodesData, innerWidth); 33 28 34 $: yScale = d3.scaleLinear().domain(yDomain).range([innerHeight, 0]); 29 35 $: xScale = d3 30 36 .scaleBand() 31 .domain( xMeasureData)37 .domain(group) 32 38 .range([0, barsWidth]) 33 39 .paddingInner(0.1) … … 38 44 .range(colors) 39 45 40 $: yTicks = getTicks(yDomain, 5);41 46 $: bandwidth = xScale.bandwidth(); 42 47 $: xSubgroup = d3.scaleBand<string>() … … 74 79 }; 75 80 </script> 76 77 <div role="tooltip" class="container" on:mousemove={handleMouseCoord} 78 bind:clientWidth={width} 79 style="--max-width: {width};" id="bar-group" > 80 <svg width={barsWidth+margin.right+margin.left} {height} class="chart" data-testid="svg-element"> 81 <g transform="translate({margin.left}, {margin.top})" class="bar-frame"> 82 {#each nodesData as node, index} 83 {#each node as subnode, i} 84 <rect y={yScale(subnode)} width={subBarWidth} x={getSubNodeX(i, index)} height={innerHeight - yScale(subnode)} fill={getFillColor(i)} 85 opacity={hoveredData ? (hoveredData[0] === subnode? '1' : '0.6') : '0.8'} 86 on:mouseover={() => handleChartHover([subnode, group[index], subGroup[i]])} 87 on:focus={() => handleChartHover([subnode, group[index], subGroup[i]])} 88 on:mouseleave={() => handleLeaveChart()} 89 tabIndex="0" 90 role="tooltip" 91 /> 81 <div id={chartID} class="barchart"> 82 <div role="tooltip" class="container" on:mousemove={handleMouseCoord} 83 bind:clientWidth={width} 84 style="--max-width: {width};" id="bar-group" > 85 <svg width={barsWidth+margin.right+margin.left} {height} class="chart" data-testid="svg-element"> 86 <g transform="translate({margin.left}, {margin.top})" class="bar-frame"> 87 {#each nodesData as node, index} 88 {#each node as subnode, i} 89 <rect y={yScale(subnode)} width={subBarWidth} x={getSubNodeX(i, index)} height={innerHeight - yScale(subnode)} fill={getFillColor(i)} 90 opacity={hoveredData ? (hoveredData[0] === subnode? '1' : '0.6') : '0.8'} 91 on:mouseover={() => handleChartHover([subnode, group[index], subGroup[i]])} 92 on:focus={() => handleChartHover([subnode, group[index], subGroup[i]])} 93 on:mouseleave={() => handleLeaveChart()} 94 tabIndex="0" 95 role="tooltip" 96 /> 97 {/each} 92 98 {/each} 93 {/each} 94 <AxisX {xScale} {barsWidth} {nodesData} {bandwidth} {yScale} {groupLabel} {group}/> 95 <AxisY {yTicks} {yScale} /> 96 </g> 97 </svg> 99 <AxisX {xScale} {barsWidth} {nodesData} {bandwidth} {yScale} {groupLabel} {group}/> 100 <AxisY {yTicks} {yScale} /> 101 </g> 102 </svg> 103 </div> 104 <div> 105 {#if hoveredData} 106 <Tooltip 107 data={hoveredData} 108 xPosition={mousePointWithMarginOffset.x} 109 yPosition={mousePointWithMarginOffset.y} 110 {groupLabel} 111 {chartID} 112 /> 113 {/if} 114 </div> 98 115 </div> 99 <div>100 {#if hoveredData}101 <Tooltip102 data={hoveredData}103 xPosition={mousePointWithMarginOffset.x}104 yPosition={mousePointWithMarginOffset.y}105 {groupLabel}106 />107 {/if}108 </div>109 110 116 <style> 111 117 #bar-group { 112 position: relative;113 118 max-width: var(--max-width); 114 119 height: fit-content; … … 117 122 padding:0 118 123 } 124 .barchart{ 125 position: relative; 126 display: flex; 127 width: 100%; 128 height: 100%; 129 } 119 130 </style> -
plot-beam/trunk/src/svelte/component/bar/Tooltip.svelte
r3009739 r3334722 5 5 export let yPosition: number; 6 6 export let groupLabel: string; 7 export let chartID: string; 8 const block = document.getElementById(chartID) 9 let xOffset = 0 10 let yOffset = 0 11 if (block) { 12 const blockRect = block.getBoundingClientRect(); 13 const scrollTop = window.pageYOffset || document.documentElement.scrollTop; 14 const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; 15 16 yOffset = blockRect.top + scrollTop; 17 xOffset = blockRect.left + scrollLeft; 18 } 7 19 </script> 8 20 9 <div class="tooltip" style="position: absolute; top: {yPosition }px; left: {xPosition}px;">21 <div class="tooltip" style="position: absolute; top: {yPosition-yOffset}px; left: {xPosition-xOffset}px;"> 10 22 <h5>{groupLabel}: {data[1]}</h5> 11 23 <h5>{data[2]}</h5> … … 18 30 margin-left: 0.3rem; 19 31 margin-right: 0.3rem; 32 font-size: 0.8rem; 20 33 } 21 34 p { 22 font-size: small;35 font-size: 0.6rem; 23 36 margin: 0; 24 37 margin-left: 0.3rem; … … 33 46 opacity: 0; 34 47 animation: fadeIn 300ms ease-in forwards; 48 overflow-x: visible; 49 overflow-x: visible; 50 z-index: 2; 35 51 } 36 52 @keyframes fadeIn { -
plot-beam/trunk/src/svelte/component/gauge/Gauge.svelte
r3009739 r3334722 3 3 import type { DefaultArcObject, Arc } from "d3"; 4 4 import {width, height} from "../../lib/canvasSetup" 5 export let valueSlices: number[]; 6 export let segmentSlices: number[]; 7 export let valueColors: string[]; 8 export let displayMarks: string[]; 9 export let displayValue: string; 10 export let segmentColors: string[]; 5 import getDisplayValue from '../../lib/getDisplayValue'; 11 6 7 export let data; 8 export let measure; 9 console.log(data, measure) 12 10 const radius: number = height / 2; 13 11 const pie = d3 … … 16 14 .endAngle((2 / 3) * Math.PI) 17 15 .sort(null); 16 $: value = data[0][1]; 17 $: valueSlice = [value - measure.ticks[0], measure.ticks[measure.ticks.length - 1]- value]; 18 console.log(18, valueSlice, measure, data) 19 const segmentColors = measure.colors; 20 $: segmentDonut= pie(measure.ticks); 21 $: valueDonut = pie(valueSlice); 22 $: segmentMarks = measure.ticks; 18 23 19 $: segmentDonut= pie(segmentSlices); 20 $: valueDonut = pie(valueSlices); 21 24 const valueColors = ['#70B1A0', '#EFEFEF']; 22 25 const valueArc: Arc<any, DefaultArcObject> = d3 23 26 .arc() … … 42 45 fill={segmentColors[i]} 43 46 id={`${slice.startAngle}`} 44 />45 <text class='segment-label' dy={-5}>46 <textPath href={`#${slice.startAngle}`} >{displayMarks[i]}</textPath>47 </text>48 <text class='segment-label' dy={-5}>49 <textPath startOffset="48%" text-anchor="end" href={`#${slice.startAngle}`}>{displayMarks.slice(-1)[0]}</textPath>50 </text>47 /> 48 <text class='segment-label' dy={-5}> 49 <textPath href={`#${slice.startAngle}`} text-anchor="start" >{getDisplayValue(segmentMarks[i-1])}</textPath> 50 </text> 51 <text class='segment-label' dy={-5}> 52 <textPath startOffset="48%" text-anchor="end" href={`#${slice.startAngle}`}>{getDisplayValue(segmentMarks[segmentMarks.length -1])}</textPath> 53 </text> 51 54 {:else} 55 {console.log(55,i, segmentMarks[i])} 52 56 <path 53 class="segments"54 d={segmentArc(slice)}55 fill={segmentColors[i]}56 id={`${slice.startAngle}`}57 />58 <text class='segment-label' dy={-5}>59 <textPath href={`#${slice.startAngle}`} >{displayMarks[i]}</textPath>60 </text>57 class="segments" 58 d={segmentArc(slice)} 59 fill={segmentColors[i]} 60 id={`${slice.startAngle}`} 61 /> 62 <text class='segment-label' dy={-5}> 63 <textPath href={`#${slice.startAngle}`} text-anchor="start">{getDisplayValue(segmentMarks[i-1])}</textPath> 64 </text> 61 65 {/if} 62 66 {/each} … … 64 68 <!-- getting the value arc --> 65 69 {#each valueDonut as slice, i} 66 <path d={valueArc(slice)} fill={valueColors[i ]} class="valueSlices" />70 <path d={valueArc(slice)} fill={valueColors[i-1]} class="valueSlices" /> 67 71 {/each} 68 <text text-anchor="middle" class="value-label" data-testid="value">{ displayValue}</text>72 <text text-anchor="middle" class="value-label" data-testid="value">{getDisplayValue(value)}</text> 69 73 </g> 70 74 </svg> -
plot-beam/trunk/src/svelte/component/lineChart/LineChart.svelte
r3073590 r3334722 1 1 <script lang="ts"> 2 export let nodesData:number[][];3 export let dimensions: string[]4 export let xTicks: string[];5 export let lines: string[];6 export let measurements: string[];7 2 import {margin, innerHeight, innerWidth, width,height} from '../../lib/canvasSetup'; 8 3 import * as d3 from 'd3'; … … 14 9 import { getExtendedRange } from '../../lib/getExtendedRange'; 15 10 import Legend from './Legend.svelte'; 11 import type { LineRawData } from 'src/svelte/appConfig/chartData'; 16 12 13 export let data:LineRawData['data']; 14 export let dimensions: LineRawData['dimensions'] 15 export let measure: LineRawData['measure'] 16 export let chartID: string; 17 17 const radius = 5 18 18 const colors = ['#9ADDC2', '#37CC90', '#29996C', '#154D36', '#002415', 19 19 '#BECDF7','#185DF2', '#1245B3', '#0B2C73', '#C4C4C4'] 20 20 21 const getTimeParser = (dimensions:string[], xTicks: string[] ) => { 22 if (dimensions[0] === "YearMonth" && xTicks[0].includes('-')) 21 $: xTicks = dimensions.groupTicks 22 $: lines = dimensions.subgroupTicks 23 $: measurement = measure.title 24 25 const getTimeParser = (dimensions:string, xTicks: string[] ) => { 26 if (dimensions === "YearMonth" && xTicks[0].includes('-')) 23 27 return d3.timeParse('%Y-%b') 24 28 … … 26 30 } 27 31 28 const getTimeFormatter = (dimensions:string [], xTicks: string[]) => {29 if (dimensions [0]=== "YearMonth" && xTicks[0].includes('-'))32 const getTimeFormatter = (dimensions:string, xTicks: string[]) => { 33 if (dimensions === "YearMonth" && xTicks[0].includes('-')) 30 34 return d3.timeFormat('%Y-%b') 31 35 32 36 return d3.timeFormat("%Y") 33 37 } 34 $: timeParser = getTimeParser(dimensions , xTicks)35 $: timeFormatter = getTimeFormatter(dimensions , xTicks)38 $: timeParser = getTimeParser(dimensions.groupTitle, xTicks) 39 $: timeFormatter = getTimeFormatter(dimensions.groupTitle, xTicks) 36 40 37 41 $: timeSeries = xTicks.map(tick => { 38 if (dimensions [0]=== "Year" && tick.length >4)42 if (dimensions.groupTitle === "Year" && tick.length >4) 39 43 return timeParser(tick.slice(0, 4)) 40 44 return timeParser(tick) 41 45 }) 42 46 43 $: yBaseRange = getBaseRange(nodesData) 44 $: yDomain = getExtendedRange(yBaseRange) 47 $: yDomain = [measure.ticks[0], measure.ticks[measure.ticks.length - 1]] 45 48 $: yScale = d3.scaleLinear().domain(yDomain).range([innerHeight, 0]) 46 49 … … 57 60 } 58 61 62 $: nodesData = xTicks.map((_: string, index: number) => { 63 return data.map((line: any) => line[1][index]); 64 }); 59 65 $: displayTicks=xTicks.length > 6? getDisplayTicks(xScale, 5, xTicks): timeSeries 60 61 $: indexArray = displayTicks.map((tick:any) => { 62 return xTicks.indexOf(timeFormatter(tick)) 63 }) 64 66 65 67 //getTicks is a function taking extented range and numbers of ticks, return the array of tick display values 66 $: yTicks = getTicks(yDomain, 4)68 $: yTicks = measure.ticks 67 69 // $: bandWidth = xScale.bandwidth() 68 70 … … 83 85 </script> 84 86 85 <div class="container" role="tooltip" 86 on:mousemove={handleMouseCoord}> 87 <svg {width} {height} class="chart" data-testid="svg-element"> 88 <g transform="translate({margin.left}, {margin.top})"> 89 <AxisX {displayTicks} {xScale} {timeFormatter} {xTicks} {timeParser} {timeSeries}/> 90 <g> 91 {#if xTicks.length > 6} 92 {#each lines as line, index} 93 {#each nodesData as node, i} 94 {#if i > 0} 95 <line x1={xScale(timeParser(xTicks[i-1]))} y1={yScale(nodesData[i-1][index])} x2={xScale(timeParser(xTicks[i]))} y2={yScale(node[index])} stroke={colors[index]} /> 96 {/if} 97 {/each} 98 {/each} 99 {:else} 100 {#each nodesData as node, index} 101 {#each node as subNode, i} 102 <circle class="intersection" cx={xScale(timeSeries[index])} cy={yScale(subNode)} fill={colors[i]} on:mouseover={() => handleCircleHover([subNode, i])} 87 <div class="linechart" id={chartID}> 88 <div class="container" role="tooltip" 89 on:mousemove={handleMouseCoord}> 90 <svg {width} {height} class="chart" data-testid="svg-element"> 91 <g transform="translate({margin.left}, {margin.top})"> 92 <AxisX {displayTicks} {xScale} {timeFormatter} {xTicks} {timeParser} {timeSeries}/> 93 <g> 94 {#if xTicks.length > 6} 95 {#each lines as line, index} 96 {#each nodesData as node, i} 97 {#if i > 0} 98 <line x1={xScale(timeParser(xTicks[i-1]))} y1={yScale(nodesData[i-1][index])} x2={xScale(timeParser(xTicks[i]))} y2={yScale(node[index])} stroke={colors[index]} /> 99 {/if} 100 {/each} 101 {/each} 102 {:else} 103 {#each nodesData as node, index} 104 <!-- each node is number array which represent value of 6 states for a time --> 105 <!-- i respresent index of the state --> 106 {#each node as subNode, i} 107 <!-- this is for the intersections --> 108 <!-- xScale(timeSeries[index]) is the x for each time --> 109 <circle class="intersection" cx={xScale(timeSeries[index])} cy={yScale(subNode)} fill={colors[i]} 110 on:mouseover={() => handleCircleHover([subNode, i])} 103 111 on:focus={() => handleCircleHover([subNode, i])} 104 112 on:mouseleave={() => handleLeaveChart()} 105 113 r={hoveredData&&hoveredData[0]==subNode? radius+3 : radius} 106 114 opacity={hoveredData ? (hoveredData[0]== subNode? '1' : '0.6') : '1'} 115 tabIndex="0" 107 116 role="tooltip"/> 117 {/each} 118 119 {#each lines as line, index} 120 {#each nodesData as node, i} 121 {#if i > 0} 122 <line x1={xScale(timeSeries[i-1])} y1={yScale(nodesData[i-1][index])} x2={xScale(timeSeries[i])} y2={yScale(node[index])} stroke={colors[index]} /> 123 {/if} 124 {/each} 125 {/each} 108 126 {/each} 109 {#each lines as line, index} 110 {#each nodesData as node, i} 111 {#if i > 0} 112 <line x1={xScale(timeSeries[i-1])} y1={yScale(nodesData[i-1][index])} x2={xScale(timeSeries[i])} y2={yScale(node[index])} stroke={colors[index]} /> 113 {/if} 114 {/each} 115 {/each} 116 {/each} 117 {/if} 127 {/if} 128 129 </g> 130 <AxisY {yScale} {yTicks} /> 131 </g> 132 <g transform="translate({margin.left+innerWidth}, {10})"> 133 <Legend {lines} {colors}/> 134 </g> 118 135 119 </g> 120 <AxisY {yScale} {yTicks} /> 121 </g> 122 <g transform="translate({margin.left+innerWidth}, {10})"> 123 <Legend {lines} {colors}/> 124 </g> 125 126 </svg> 136 </svg> 137 </div> 138 139 {#if hoveredData} 140 <Tooltip data={hoveredData} xPosition={mousePointWithMarginOffset.x} 141 yPosition={mousePointWithMarginOffset.y} {lines} {measurement} {chartID}/> 142 {/if} 127 143 </div> 128 144 129 130 {#if hoveredData} 131 <Tooltip data={hoveredData} xPosition={mousePointWithMarginOffset.x} 132 yPosition={mousePointWithMarginOffset.y} {lines} {measurements}/> 133 {/if} 134 145 <style> 146 circle { 147 transition: all 300ms ease; 148 cursor: pointer; 149 } 150 .linechart{ 151 position: relative; 152 display: flex; 153 width: 100%; 154 height: 100%; 155 overflow-x: visible; 156 overflow-y: visible; 157 } 158 </style> -
plot-beam/trunk/src/svelte/component/lineChart/Tooltip.svelte
r3009739 r3334722 1 1 <script lang="ts"> 2 // data is [value of intersection, state index] 2 3 export let data: number[]; 3 4 export let xPosition: number; 4 5 export let yPosition: number; 5 6 export let lines: string[]; 6 export let measurements: string[]; 7 export let measurement: string[]; 8 export let chartID; 9 7 10 import getTooltipValue from "../../lib/getTooltipValue"; 8 import {margin} from "../../lib/canvasSetup" 11 12 let xOffset = 0 13 let yOffset = 0 14 const block = document.getElementById(chartID); 15 if (block) { 16 const blockRect = block.getBoundingClientRect(); 17 const scrollTop = window.pageYOffset || document.documentElement.scrollTop; 18 const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; 19 20 yOffset = blockRect.top + scrollTop; 21 xOffset = blockRect.left + scrollLeft; 22 } 9 23 </script> 10 24 11 <div class="tooltip" style="position: absolute; top: {yPosition+margin.top-10}px; left: {xPosition+50}px;"> 12 <h5>{lines[data[1]]}</h5> 13 <p>{measurements[0]}: {getTooltipValue(data[0])}</p> 14 </div> 25 26 <div class="tooltip" style="position: absolute; top: {yPosition-yOffset}px; left: {xPosition-xOffset}px;"> 27 <h5>{lines[data[1]]}</h5> 28 <p>{measurement}: {getTooltipValue(data[0])}</p> 29 </div> 30 15 31 16 32 … … 20 36 margin-left: 0.3rem; 21 37 margin-right: 0.3rem; 38 font-size: 0.8rem; 22 39 } 23 40 p { 24 font-size: small;25 41 margin: 0; 26 42 margin-left: 0.3rem; 27 43 margin-right: 0.3rem; 44 font-size: 0.6rem; 28 45 } 29 46 .tooltip { -
plot-beam/trunk/src/svelte/component/scatterPlot/AxisX.svelte
r3009739 r3334722 2 2 import { getNumberOfDigits } from '../../lib/getExtendedRange'; 3 3 import { innerHeight, innerWidth} from "../../lib/canvasSetup"; 4 import getDisplayValue from '../../lib/getDisplayValue'; 4 5 export let xMeasure: string; 5 6 export let xTicks: number[]; … … 13 14 {#if index !== 0 } 14 15 <line x1={xScale(tick)} y1={innerHeight} x2={xScale(tick)} y2={innerHeight-6} stroke="grey" /> 15 <text class="label" x={xScale(tick)} y={innerHeight} text-anchor="middle" dy={15}>{ get NumberOfDigits(tick) > 3? `${tick/1000}k` : tick}</text>16 <text class="label" x={xScale(tick)} y={innerHeight} text-anchor="middle" dy={15}>{ getDisplayValue(tick) }</text> 16 17 {:else} 17 <text class="label" x={xScale(tick)} y={innerHeight} text-anchor="start" dy={15}>{ get NumberOfDigits(tick) > 3? `${tick/1000}k` : tick}</text>18 <text class="label" x={xScale(tick)} y={innerHeight} text-anchor="start" dy={15}>{ getDisplayValue(tick) }</text> 18 19 {/if} 19 20 {/each} -
plot-beam/trunk/src/svelte/component/scatterPlot/ScatterPlot.svelte
r3009739 r3334722 5 5 import AxisY from "./AxisY.svelte"; 6 6 import Tooltip from "./Tooltip.svelte"; 7 import {getExtendedRange }from "../../lib/getExtendedRange"; 8 import getTicks from "../../lib/getTicks"; 7 import type { ScatterplotRawData } from "src/svelte/appConfig/chartData"; 8 9 export let data: ScatterplotRawData['data']; 10 export let dimensions: ScatterplotRawData['dimensions']; 11 export let measure: ScatterplotRawData['measure']; 12 export let chartID: string; 9 13 10 export let xMeasure: string; 11 export let yMeasure: string; 12 export let nodesData: number[][]; 13 export let dimension: string; 14 export let nodeLabel: string[]; 14 $: xMeasure = measure.title[0] 15 $: yMeasure = measure.title[1] 15 16 16 $: xMeasureData = nodesData.map(row=> row[0]) 17 $: yMeasureData = nodesData.map(row=> row[1]) 18 19 $: yBaseRange = [Math.min(...yMeasureData), Math.max(...yMeasureData)] 20 $: xBaseRange = [Math.min(...xMeasureData), Math.max(...xMeasureData)] 21 22 $: xDomain = getExtendedRange(xBaseRange) 23 $: yDomain = getExtendedRange(yBaseRange) 17 $: xDomain = [measure.xTicks[0], measure.xTicks[measure.xTicks.length-1]] 18 $: yDomain = [measure.yTicks[0], measure.yTicks[measure.xTicks.length-1]] 24 19 25 20 $: xScale = d3.scaleLinear().domain(xDomain).range([0, innerWidth]) 26 21 $: yScale = d3.scaleLinear().domain(yDomain).range([innerHeight, 0]) 27 $: yTicks = getTicks(yDomain, 5) 28 $: xTicks = getTicks(xDomain, 5) 22 $: yTicks = measure.yTicks 23 $: xTicks = measure.xTicks 24 $: nodesData = data 25 $: nodeLabel = dimensions.groupTicks 29 26 30 27 let hoveredData: number[] | null … … 44 41 </script> 45 42 46 <div 47 role="tooltip" 48 class="container" 49 on:mousemove={handleMouseCoord} 50 > 51 <svg {width} {height} class="chart" data-testid="svg-element"> 52 <g transform="translate({margin.left}, {margin.top})"> 53 {#each nodesData as row, index} 54 <circle class="circle" cx={xScale(row[0])} cy={yScale(row[1])} 55 r={hoveredData && hoveredData === row ? '12' : '8'} 56 opacity={hoveredData ? (hoveredData[2] === index ? '1' : '0.6') : '1'} 57 fill="#37cc90" 58 stroke="#010101" 59 on:mouseover={() => handleCircleHover([...row, index])} 60 on:focus={() => handleCircleHover([...row, index])} 61 on:mouseleave={() => handleLeaveChart()} 62 tabIndex="0" role="tooltip"/> 63 {/each} 64 <AxisX {xMeasure} {xTicks} {xScale} /> 65 <AxisY {yMeasure} {yTicks} {yScale} /> 66 </g> 67 </svg> 43 <div class="scatterplot" id={chartID}> 44 <div 45 role="tooltip" 46 class="container" 47 on:mousemove={handleMouseCoord} 48 > 49 <svg {width} {height} class="chart" data-testid="svg-element"> 50 <g transform="translate({margin.left}, {margin.top})"> 51 {#each data as row, index} 52 <circle class="circle" cx={xScale(row[1][0])} cy={yScale(row[1][1])} 53 r={hoveredData && hoveredData === row[1]? '12' : '8'} 54 opacity={hoveredData ? (hoveredData[2] === index ? '1' : '0.6') : '1'} 55 fill="#37cc90" 56 stroke="#010101" 57 on:mouseover={() => handleCircleHover([...row[1], index])} 58 on:focus={() => handleCircleHover([...row[1], index])} 59 on:mouseleave={() => handleLeaveChart()} 60 tabIndex="0" role="tooltip"/> 61 {/each} 62 <AxisX {xMeasure} {xTicks} {xScale} /> 63 <AxisY {yMeasure} {yTicks} {yScale} /> 64 </g> 65 </svg> 68 66 </div> 69 {#if hoveredData} 70 <Tooltip 71 {xMeasure} 72 {yMeasure} 73 data={hoveredData} 74 xPosition={mousePointWithMarginOffset.x} 75 yPosition={mousePointWithMarginOffset.y} 76 {nodeLabel} 77 /> 78 {/if} 79 67 {#if hoveredData} 68 <Tooltip 69 {xMeasure} 70 {yMeasure} 71 data={hoveredData} 72 xPosition={mousePointWithMarginOffset.x} 73 yPosition={mousePointWithMarginOffset.y} 74 {nodeLabel} 75 {chartID} 76 /> 77 {/if} 78 </div> 80 79 <style> 81 80 circle { … … 83 82 cursor: pointer; 84 83 } 84 .scatterplot{ 85 position: relative; 86 display: flex; 87 width: 100%; 88 height: 100%; 89 overflow-x: visible; 90 overflow-y: visible; 91 } 85 92 </style> -
plot-beam/trunk/src/svelte/component/scatterPlot/Tooltip.svelte
r3009739 r3334722 7 7 export let yMeasure: string; 8 8 export let nodeLabel: string[]; 9 export let chartID: string; 9 10 10 $: xAdjusted = xPosition - 50; 11 $: yAdjusted = yPosition - 50; 11 const block = document.getElementById(chartID); 12 let xOffset = 0 13 let yOffset = 0 14 if (block) { 15 const blockRect = block.getBoundingClientRect(); 16 const scrollTop = window.pageYOffset || document.documentElement.scrollTop; 17 const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; 18 19 yOffset = blockRect.top + scrollTop; 20 xOffset = blockRect.left + scrollLeft; 21 } 12 22 </script> 13 23 14 <div class="tooltip" style="position: absolute; top: {y Adjusted}px; left: {xAdjusted}px;">24 <div class="tooltip" style="position: absolute; top: {yPosition-yOffset}px; left: {xPosition-xOffset}px;"> 15 25 <h5>{nodeLabel[data[2]]}</h5> 16 26 <p>{xMeasure}: {getTooltipValue(data[0])}</p> … … 24 34 margin-left: 0.3rem; 25 35 margin-right: 0.3rem; 36 font-size: 0.8rem; 26 37 } 27 38 p { … … 30 41 margin-left: 0.3rem; 31 42 margin-right: 0.3rem; 43 font-size: 0.6rem; 32 44 } 33 45 .tooltip { … … 39 51 opacity: 0; 40 52 animation: fadeIn 300ms ease-in forwards; 53 overflow-x: visible; 54 overflow-y: visible; 55 z-index: 2; 41 56 } 42 57 @keyframes fadeIn { -
plot-beam/trunk/src/svelte/lib/bar/getBarsWidth.ts
r3009739 r3334722 1 1 const getBarsWidth = ( 2 group: string[],3 subGroup: string[], 2 group: string[], 3 subGroup: string[], 4 4 nodesData: number[][], 5 5 innerWidth: number … … 7 7 let barWidth; 8 8 //check if it is a grouped bar 9 if ( subGroup.length>1) {10 barWidth = 31 *subGroup.length9 if ( subGroup.length > 1 ) { 10 barWidth = 31 * subGroup.length; 11 11 } else { 12 barWidth = 4012 barWidth = 40; 13 13 } 14 14 const barsWidth = barWidth * group.length; 15 16 if ( innerWidth < barsWidth ) 17 return barsWidth; 18 15 16 if ( innerWidth < barsWidth ) return barsWidth; 17 19 18 return innerWidth; 20 19 }; -
plot-beam/trunk/src/svelte/lib/getBaseRange.test.ts
r3009739 r3334722 4 4 it( 'base tst', () => { 5 5 const testArray: number[][] = [ 6 [ 23, 49, 198 ],7 [ 223, 249, 698 ],8 [ 77, 97, 54 ],6 [ 23, 49, 198 ], 7 [ 223, 249, 698 ], 8 [ 77, 97, 54 ], 9 9 [ 628, 29, 763 ], 10 10 ]; … … 18 18 const testArray: number[][] = [ 19 19 [ 87666.29400000005, 72043.92419999996, 208757.69999999992 ], 20 [ 458871.0101, 363073.9277000001, 580147.4999999994 ],20 [ 458871.0101, 363073.9277000001, 580147.4999999994 ], 21 21 [ 1101379.7817, 868841.0968000006, 1280426.099999999 ], 22 22 [ 1785036.1851000001, 1421877.3500000006, 1222286.9999999993 ], -
plot-beam/trunk/src/svelte/lib/getDisplayValue.ts
r3009739 r3334722 1 1 import { getNumberOfDigits } from './getExtendedRange'; 2 2 3 const getDisplayValue = ( value: number ) => { 3 const getDisplayValue = ( value: number | string ) => { 4 if ( typeof value === 'string' ) { 5 const parsedValue = parseFloat( value ); 6 if ( isNaN( parsedValue ) ) return value; 7 value = parsedValue; 8 } 4 9 const trimedValue = Math.round( value ); 5 10 const digits = getNumberOfDigits( trimedValue );
Note: See TracChangeset
for help on using the changeset viewer.