diff --git a/404.html b/404.html index 126ba43..ba41395 100644 --- a/404.html +++ b/404.html @@ -13,13 +13,13 @@ - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- + \ No newline at end of file diff --git a/assets/js/cf38f87c.23bc6694.js b/assets/js/cf38f87c.23bc6694.js new file mode 100644 index 0000000..363fece --- /dev/null +++ b/assets/js/cf38f87c.23bc6694.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkcal_heatmap_doc=self.webpackChunkcal_heatmap_doc||[]).push([[3680],{3905:(e,t,a)=>{a.d(t,{Zo:()=>s,kt:()=>h});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var u=n.createContext({}),p=function(e){var t=n.useContext(u),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},s=function(e){var t=p(e.components);return n.createElement(u.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,u=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=p(a),m=r,h=d["".concat(u,".").concat(m)]||d[m]||c[m]||o;return a?n.createElement(h,i(i({ref:t},s),{},{components:a})):n.createElement(h,i({ref:t},s))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=m;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l[d]="string"==typeof e?e:r,i[1]=l;for(var p=2;p{a.r(t),a.d(t,{assets:()=>u,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var n=a(7462),r=(a(7294),a(3905));const o={title:"data",sidebar_position:6},i=void 0,l={unversionedId:"options/data",id:"options/data",title:"data",description:"Specify how to fetch and process the data used to fill the calendar",source:"@site/docs/options/data.md",sourceDirName:"options",slug:"/options/data",permalink:"/docs/options/data",draft:!1,editUrl:"https://github.com/wa0x6e/cal-heatmap-doc/edit/main/docs/options/data.md",tags:[],version:"current",sidebarPosition:6,frontMatter:{title:"data",sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"date",permalink:"/docs/options/date"},next:{title:"verticalOrientation",permalink:"/docs/options/verticalOrientation"}},u={},p=[{value:"source",id:"source",level:2},{value:"Using a local object",id:"using-a-local-object",level:3},{value:"Fetching data from a remote source",id:"fetching-data-from-a-remote-source",level:3},{value:"Injecting dynamic date",id:"injecting-dynamic-date",level:4},{value:"type",id:"type",level:2},{value:"requestInit",id:"requestinit",level:2},{value:"x",id:"x",level:2},{value:"Example",id:"example",level:4},{value:"y",id:"y",level:2},{value:"Example",id:"example-1",level:4},{value:"groupY",id:"groupy",level:2},{value:"Example",id:"example-2",level:4},{value:"defaultValue",id:"defaultvalue",level:2}],s={toc:p},d="wrapper";function c(e){let{components:t,...a}=e;return(0,r.kt)(d,(0,n.Z)({},s,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",{className:"subhead"},"Specify how to fetch and process the data used to fill the calendar"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"type DataRecord = Record;\ntype DataGroupType = 'sum' | 'count' | 'min' | 'max' | 'average';\n\ntype DataOptions = {\n source: string | DataRecord[],\n type: 'json' | 'csv' | 'tsv' | 'txt',\n requestInit: object,\n x: string | ((datum: DataRecord) => number),\n y: string | ((datum: DataRecord) => number),\n groupY:\n | DataGroupType\n | ((values: (number | string | null)[]) => number | string | null),\n defaultValue: null | number | string,\n};\n")),(0,r.kt)("p",null,"The calendar is expecting an array of objects as input.",(0,r.kt)("br",{parentName:"p"}),"\n","There is no expected pre-defined structure for the object,\nbut it must at least have one or more property for the date,\nand another one for the value, which is usually a number, but string is also accepted"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Classic object"',title:'"Classic','object"':!0},"[\n { date: '2012-01-01', value: 3 },\n { date: '2012-01-02', value: 6 },\n ...\n];\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Using timestamp"',title:'"Using','timestamp"':!0},"[\n { t: 1673388319933, p: 3, v: 'Asia' },\n { t: 1673388319934, p: 6, v: 'Europe' },\n ...\n];\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Using multiple properties to define a date"',title:'"Using',multiple:!0,properties:!0,to:!0,define:!0,a:!0,'date"':!0},"[\n { year: 2020, month: 1, day: 1, temperature: 38 },\n ...\n];\n")),(0,r.kt)("p",null,"More options are available below to instruct the calendar on\nhow to fetch, read and extract the date and value from your dataset."),(0,r.kt)("hr",null),(0,r.kt)("h2",{id:"source"},(0,r.kt)("inlineCode",{parentName:"h2"},"source")),(0,r.kt)("p",null,"Data used to populate the calendar."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"source: string | DataRecord[],\n")),(0,r.kt)("p",null,"There are 2 ways to pass your data to the calendar:"),(0,r.kt)("h3",{id:"using-a-local-object"},"Using a local object"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"// highlight-start\nconst data = [\n { date: '2012-01-01', value: 3 },\n { date: '2012-01-02', value: 6 },\n];\n// highlight-end\n\nconst cal = new CalHeatmap();\ncal.paint({\n // highlight-next-line\n data: { source: data },\n});\n")),(0,r.kt)("h3",{id:"fetching-data-from-a-remote-source"},"Fetching data from a remote source"),(0,r.kt)("p",null,"A ",(0,r.kt)("inlineCode",{parentName:"p"},"string")," value will be interpreted as an url, and the data\nwill be retrieved via a ",(0,r.kt)("inlineCode",{parentName:"p"},"GET")," request."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"const cal = new CalHeatmap();\ncal.paint({\n // highlight-next-line\n data: { source: 'https://your-api.com/data.json' },\n});\n")),(0,r.kt)("h4",{id:"injecting-dynamic-date"},"Injecting dynamic date"),(0,r.kt)("p",null,"2 special tokens are available to customize your url,\nin order to limit the data time range from your remote source."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"{{start=XXX}}")," will be replaced by the start of the first subDomain of the calendar"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"{{end=XXX}}")," will be replaced by the end of the last subDomain of the calendar")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"XXX")," should be replaced by any ",(0,r.kt)("a",{parentName:"p",href:"https://day.js.org/docs/en/display/format"},"dayjs format token")," (",(0,r.kt)("a",{parentName:"p",href:"https://day.js.org/docs/en/plugin/advanced-format"},"Advanced tokens")," are also accepted)"),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"The ",(0,r.kt)("inlineCode",{parentName:"p"},"start")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"end")," time range are both inclusive.")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"The tokens' value will dynamically update on ",(0,r.kt)("a",{parentName:"p",href:"/docs/API/navigation/"},"navigation"),".")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Usage"',title:'"Usage"'},"const cal = new CalHeatmap();\ncal.paint({\n date: { start: new Date('2020-01-01') },\n // highlight-next-line\n data: {\n source:\n 'https://your-api.com/data?start={{start=YYYY-MM-DD}}&end={{end=[year-]YYYY}}',\n },\n});\n")),(0,r.kt)("p",null,"The above ",(0,r.kt)("inlineCode",{parentName:"p"},"date.source")," will output something like:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"https://your-api.com/data?start=2020-01-01&end=year-2020\n")),(0,r.kt)("p",null,"If the remote source is behind authentication, or requires additional request\ncustomization, see ",(0,r.kt)("a",{parentName:"p",href:"#requestinit"},"requestInit"),"."),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch"},(0,r.kt)("inlineCode",{parentName:"a"},"Fetch"))," is used under the hood to load the remote resource.\nEnsure that your endpoint has ",(0,r.kt)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"},"CORS")," setup properly.")),(0,r.kt)("h2",{id:"type"},(0,r.kt)("inlineCode",{parentName:"h2"},"type")),(0,r.kt)("p",null,"Parser used to interpret the data returned by your url source."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"type: 'json' | 'csv' | 'tsv' | 'txt',\n")),(0,r.kt)("p",null,"The parser will interpret the data, and convert it to an array of DataRecord."),(0,r.kt)("p",null,"Default: ",(0,r.kt)("inlineCode",{parentName:"p"},"json")),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"This option is used only when the ",(0,r.kt)("a",{parentName:"p",href:"#source"},(0,r.kt)("inlineCode",{parentName:"a"},"source"))," is an url.")),(0,r.kt)("h2",{id:"requestinit"},(0,r.kt)("inlineCode",{parentName:"h2"},"requestInit")),(0,r.kt)("p",null,"Additional ",(0,r.kt)("a",{parentName:"p",href:"https://fetch.spec.whatwg.org/#requestinit"},"requestInit")," options, send along your data request."),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/d3/d3-fetch"},"d3-fetch")," is used under the hood to handle all network requests. See their documentation for further information and usage."),(0,r.kt)("p",null,"Default: ",(0,r.kt)("inlineCode",{parentName:"p"},"{}")),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"This option is used only when the ",(0,r.kt)("inlineCode",{parentName:"p"},"source")," is an url.")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Usage"',title:'"Usage"'},"{\n method: 'POST', // *GET, POST, PUT, DELETE, etc.\n mode: 'cors', // no-cors, *cors, same-origin\n cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached\n credentials: 'same-origin', // include, *same-origin, omit\n headers: {\n 'Content-Type': 'application/json'\n // 'Content-Type': 'application/x-www-form-urlencoded',\n },\n redirect: 'follow', // manual, *follow, error\n referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url\n }\n")),(0,r.kt)("h2",{id:"x"},(0,r.kt)("inlineCode",{parentName:"h2"},"x")),(0,r.kt)("p",null,"Property name of the date, or a function returning a timestamp.",(0,r.kt)("br",{parentName:"p"}),"\n","Instruct the calendar how to extract the ",(0,r.kt)("em",{parentName:"p"},"date")," property from your data."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"x: string | ((datum: DataRecord) => number),\n")),(0,r.kt)("p",null,"You can either pass a:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"string"),": key name of the property holding the date, in your datum object. The date will be parsed using ",(0,r.kt)("a",{parentName:"li",href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date"},(0,r.kt)("inlineCode",{parentName:"a"},"Date.parse")),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"function"),": function taking the datum as argument, and should return a timestamp")),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"If your date is a string (e.g. '2020-01-01T00:00:00'), ensure that its format is ",(0,r.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/ISO_8601"},"ISO 8601")," compliant (",(0,r.kt)("inlineCode",{parentName:"p"},"YYYY-MM-DDTHH:mm:ss.sssZ"),"), or it may lead to inconsistency/precision loss."),(0,r.kt)("p",{parentName:"admonition"},"If possible, we recommend to always use timestamp, to avoid all timezone related issues.")),(0,r.kt)("h4",{id:"example"},"Example"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Extract date using property name"',title:'"Extract',date:!0,using:!0,property:!0,'name"':!0},"// highlight-next-line\nvar data = [{ column1: '2012-01-01', column2: 3 }];\n\ncal.paint({\n // highlight-next-line\n data: { source: data, x: 'column1' },\n});\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Extract date using a custom function"',title:'"Extract',date:!0,using:!0,a:!0,custom:!0,'function"':!0},"// highlight-next-line\nvar data = [{ column1: '2012-01-01', column2: 3 }];\n\ncal.paint({\n data: {\n source: data,\n // highlight-start\n x: datum => {\n return +new Date(datum['column1']);\n },\n // highlight-end\n },\n});\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Compute date from multiple properties"',title:'"Compute',date:!0,from:!0,multiple:!0,'properties"':!0},"// highlight-next-line\nvar data = [{ year: 2020, month: 1, value: 3 }];\n\ncal.paint({\n data: {\n source: data,\n // highlight-start\n x: datum => {\n return +new Date(datum['year'], datum['month'] - 1, 1);\n },\n // highlight-end\n },\n});\n")),(0,r.kt)("h2",{id:"y"},(0,r.kt)("inlineCode",{parentName:"h2"},"y")),(0,r.kt)("p",null,"Property name of the the value, or a function returning the value.",(0,r.kt)("br",{parentName:"p"}),"\n","Instruct the calendar how to extract the ",(0,r.kt)("em",{parentName:"p"},"value")," property from your data."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"y: string | ((datum: DataRecord) => number | string),\n")),(0,r.kt)("p",null,"You can either pass a:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"string"),": key name of the property holding the value, in your datum object. The value should be a number."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"function"),": function taking the datum as argument, and should return the value, as a number or a string")),(0,r.kt)("h4",{id:"example-1"},"Example"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Extract value using property name"',title:'"Extract',value:!0,using:!0,property:!0,'name"':!0},"// highlight-next-line\nvar data = [{ column1: '2012-01-01', column2: 3 }];\n\ncal.paint({\n // highlight-next-line\n data: { source: data, y: 'column2' },\n});\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Extract value using a built-in function"',title:'"Extract',value:!0,using:!0,a:!0,"built-in":!0,'function"':!0},"// highlight-next-line\nvar data = [{ date: '2012-01-01', high: '30', low: '16' }];\n\ncal.paint({\n data: {\n source: data,\n // highlight-start\n y: datum => {\n // You can use the function to pre-process your values\n return +datum['high'] + +datum['low']) / 2;\n },\n // highlight-end\n },\n});\n")),(0,r.kt)("h2",{id:"groupy"},(0,r.kt)("inlineCode",{parentName:"h2"},"groupY")),(0,r.kt)("p",null,"Aggregate function, to group all values from the same subDomain."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"type DataGroupType = 'sum' | 'count' | 'min' | 'max' | 'average';\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"groupY:\n | DataGroupType\n | ((values: (number | string | null)[]) => number | string | null),\n")),(0,r.kt)("p",null,"You can either pass a:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"string"),": name of a built-in aggregate function (see ",(0,r.kt)("em",{parentName:"li"},"DataGroupType"),"), only available if your values are numeric"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"function"),": function taking an array of datum from the same subDomain, and should return a new aggregated value.")),(0,r.kt)("p",null,"Default: ",(0,r.kt)("inlineCode",{parentName:"p"},"sum")),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"If your values are non-numeric, you have to use ",(0,r.kt)("inlineCode",{parentName:"p"},"count"),", or implement your own aggregation strategy")),(0,r.kt)("h4",{id:"example-2"},"Example"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="data.js"',title:'"data.js"'},"var data = [\n { column1: '2012-01-01', column2: 3 },\n { column1: '2012-01-01', column2: 4 },\n { column1: '2012-01-02', column2: 5 },\n];\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Group using a built-in function"',title:'"Group',using:!0,a:!0,"built-in":!0,'function"':!0},"cal.paint({\n data: {\n source: data,\n x: 'column1',\n y: 'column2',\n // highlight-next-line\n groupY: 'sum',\n },\n});\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Group using a custom function"',title:'"Group',using:!0,a:!0,custom:!0,'function"':!0},"cal.paint({\n data: {\n source: data,\n x: 'column1',\n y: 'column2',\n // highlight-start\n groupY: data => {\n // data === [3, 4, 5]\n return data.reduce((a, b) => a + b, 0);\n },\n // highlight-end\n },\n});\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"groupY")," also supports values with non-numeric type, such as"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="data.js"',title:'"data.js"'},"var data = [\n { column1: '2012-01-01', column2: 'Asia' },\n { column1: '2012-01-01', column2: 'Europe' },\n { column1: '2012-01-02', column2: 'Asia' },\n];\n")),(0,r.kt)("p",null,"In that case, only the ",(0,r.kt)("inlineCode",{parentName:"p"},"count")," DataGroupType will be available, and you should implement\nyour own ",(0,r.kt)("inlineCode",{parentName:"p"},"groupY")," function if you are grouping your values by another strategy."),(0,r.kt)("h2",{id:"defaultvalue"},(0,r.kt)("inlineCode",{parentName:"h2"},"defaultValue")),(0,r.kt)("p",null,"Default value to use when your dataset does not have a value for a date."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"defaultValue: null | number | string,\n")),(0,r.kt)("p",null,"Default: ",(0,r.kt)("inlineCode",{parentName:"p"},"null")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"The most common use case will be to set it to ",(0,r.kt)("inlineCode",{parentName:"p"},"0")),(0,r.kt)("p",{parentName:"admonition"},"This option used to be known as ",(0,r.kt)("inlineCode",{parentName:"p"},"considerMissingDataAsZero")," in the previous versions")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/cf38f87c.fc49bb71.js b/assets/js/cf38f87c.fc49bb71.js deleted file mode 100644 index 2fca79d..0000000 --- a/assets/js/cf38f87c.fc49bb71.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkcal_heatmap_doc=self.webpackChunkcal_heatmap_doc||[]).push([[3680],{3905:(e,t,a)=>{a.d(t,{Zo:()=>s,kt:()=>h});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var u=n.createContext({}),p=function(e){var t=n.useContext(u),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},s=function(e){var t=p(e.components);return n.createElement(u.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,u=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=p(a),m=r,h=d["".concat(u,".").concat(m)]||d[m]||c[m]||o;return a?n.createElement(h,i(i({ref:t},s),{},{components:a})):n.createElement(h,i({ref:t},s))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=m;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l[d]="string"==typeof e?e:r,i[1]=l;for(var p=2;p{a.r(t),a.d(t,{assets:()=>u,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var n=a(7462),r=(a(7294),a(3905));const o={title:"data",sidebar_position:6},i=void 0,l={unversionedId:"options/data",id:"options/data",title:"data",description:"Specify how to fetch and process the data used to fill the calendar",source:"@site/docs/options/data.md",sourceDirName:"options",slug:"/options/data",permalink:"/docs/options/data",draft:!1,editUrl:"https://github.com/wa0x6e/cal-heatmap-doc/edit/main/docs/options/data.md",tags:[],version:"current",sidebarPosition:6,frontMatter:{title:"data",sidebar_position:6},sidebar:"tutorialSidebar",previous:{title:"date",permalink:"/docs/options/date"},next:{title:"verticalOrientation",permalink:"/docs/options/verticalOrientation"}},u={},p=[{value:"source",id:"source",level:2},{value:"Using a local object",id:"using-a-local-object",level:3},{value:"Fetching data from a remote source",id:"fetching-data-from-a-remote-source",level:3},{value:"Injecting dynamic date",id:"injecting-dynamic-date",level:4},{value:"type",id:"type",level:2},{value:"requestInit",id:"requestinit",level:2},{value:"x",id:"x",level:2},{value:"Example",id:"example",level:4},{value:"y",id:"y",level:2},{value:"Example",id:"example-1",level:4},{value:"groupY",id:"groupy",level:2},{value:"Example",id:"example-2",level:4},{value:"defaultValue",id:"defaultvalue",level:2}],s={toc:p},d="wrapper";function c(e){let{components:t,...a}=e;return(0,r.kt)(d,(0,n.Z)({},s,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",{className:"subhead"},"Specify how to fetch and process the data used to fill the calendar"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"type DataRecord = Record;\ntype DataGroupType = 'sum' | 'count' | 'min' | 'max' | 'median';\n\ntype DataOptions = {\n source: string | DataRecord[],\n type: 'json' | 'csv' | 'tsv' | 'txt',\n requestInit: object,\n x: string | ((datum: DataRecord) => number),\n y: string | ((datum: DataRecord) => number),\n groupY:\n | DataGroupType\n | ((values: (number | string | null)[]) => number | string | null),\n defaultValue: null | number | string,\n};\n")),(0,r.kt)("p",null,"The calendar is expecting an array of objects as input.",(0,r.kt)("br",{parentName:"p"}),"\n","There is no expected pre-defined structure for the object,\nbut it must at least have one or more property for the date,\nand another one for the value, which is usually a number, but string is also accepted"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Classic object"',title:'"Classic','object"':!0},"[\n { date: '2012-01-01', value: 3 },\n { date: '2012-01-02', value: 6 },\n ...\n];\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Using timestamp"',title:'"Using','timestamp"':!0},"[\n { t: 1673388319933, p: 3, v: 'Asia' },\n { t: 1673388319934, p: 6, v: 'Europe' },\n ...\n];\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Using multiple properties to define a date"',title:'"Using',multiple:!0,properties:!0,to:!0,define:!0,a:!0,'date"':!0},"[\n { year: 2020, month: 1, day: 1, temperature: 38 },\n ...\n];\n")),(0,r.kt)("p",null,"More options are available below to instruct the calendar on\nhow to fetch, read and extract the date and value from your dataset."),(0,r.kt)("hr",null),(0,r.kt)("h2",{id:"source"},(0,r.kt)("inlineCode",{parentName:"h2"},"source")),(0,r.kt)("p",null,"Data used to populate the calendar."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"source: string | DataRecord[],\n")),(0,r.kt)("p",null,"There are 2 ways to pass your data to the calendar:"),(0,r.kt)("h3",{id:"using-a-local-object"},"Using a local object"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"// highlight-start\nconst data = [\n { date: '2012-01-01', value: 3 },\n { date: '2012-01-02', value: 6 },\n];\n// highlight-end\n\nconst cal = new CalHeatmap();\ncal.paint({\n // highlight-next-line\n data: { source: data },\n});\n")),(0,r.kt)("h3",{id:"fetching-data-from-a-remote-source"},"Fetching data from a remote source"),(0,r.kt)("p",null,"A ",(0,r.kt)("inlineCode",{parentName:"p"},"string")," value will be interpreted as an url, and the data\nwill be retrieved via a ",(0,r.kt)("inlineCode",{parentName:"p"},"GET")," request."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"const cal = new CalHeatmap();\ncal.paint({\n // highlight-next-line\n data: { source: 'https://your-api.com/data.json' },\n});\n")),(0,r.kt)("h4",{id:"injecting-dynamic-date"},"Injecting dynamic date"),(0,r.kt)("p",null,"2 special tokens are available to customize your url,\nin order to limit the data time range from your remote source."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"{{start=XXX}}")," will be replaced by the start of the first subDomain of the calendar"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"{{end=XXX}}")," will be replaced by the end of the last subDomain of the calendar")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"XXX")," should be replaced by any ",(0,r.kt)("a",{parentName:"p",href:"https://day.js.org/docs/en/display/format"},"dayjs format token")," (",(0,r.kt)("a",{parentName:"p",href:"https://day.js.org/docs/en/plugin/advanced-format"},"Advanced tokens")," are also accepted)"),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"The ",(0,r.kt)("inlineCode",{parentName:"p"},"start")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"end")," time range are both inclusive.")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"The tokens' value will dynamically update on ",(0,r.kt)("a",{parentName:"p",href:"/docs/API/navigation/"},"navigation"),".")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Usage"',title:'"Usage"'},"const cal = new CalHeatmap();\ncal.paint({\n date: { start: new Date('2020-01-01') },\n // highlight-next-line\n data: {\n source:\n 'https://your-api.com/data?start={{start=YYYY-MM-DD}}&end={{end=[year-]YYYY}}',\n },\n});\n")),(0,r.kt)("p",null,"The above ",(0,r.kt)("inlineCode",{parentName:"p"},"date.source")," will output something like:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"https://your-api.com/data?start=2020-01-01&end=year-2020\n")),(0,r.kt)("p",null,"If the remote source is behind authentication, or requires additional request\ncustomization, see ",(0,r.kt)("a",{parentName:"p",href:"#requestinit"},"requestInit"),"."),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},(0,r.kt)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch"},(0,r.kt)("inlineCode",{parentName:"a"},"Fetch"))," is used under the hood to load the remote resource.\nEnsure that your endpoint has ",(0,r.kt)("a",{parentName:"p",href:"https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"},"CORS")," setup properly.")),(0,r.kt)("h2",{id:"type"},(0,r.kt)("inlineCode",{parentName:"h2"},"type")),(0,r.kt)("p",null,"Parser used to interpret the data returned by your url source."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"type: 'json' | 'csv' | 'tsv' | 'txt',\n")),(0,r.kt)("p",null,"The parser will interpret the data, and convert it to an array of DataRecord."),(0,r.kt)("p",null,"Default: ",(0,r.kt)("inlineCode",{parentName:"p"},"json")),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"This option is used only when the ",(0,r.kt)("a",{parentName:"p",href:"#source"},(0,r.kt)("inlineCode",{parentName:"a"},"source"))," is an url.")),(0,r.kt)("h2",{id:"requestinit"},(0,r.kt)("inlineCode",{parentName:"h2"},"requestInit")),(0,r.kt)("p",null,"Additional ",(0,r.kt)("a",{parentName:"p",href:"https://fetch.spec.whatwg.org/#requestinit"},"requestInit")," options, send along your data request."),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/d3/d3-fetch"},"d3-fetch")," is used under the hood to handle all network requests. See their documentation for further information and usage."),(0,r.kt)("p",null,"Default: ",(0,r.kt)("inlineCode",{parentName:"p"},"{}")),(0,r.kt)("admonition",{type:"note"},(0,r.kt)("p",{parentName:"admonition"},"This option is used only when the ",(0,r.kt)("inlineCode",{parentName:"p"},"source")," is an url.")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Usage"',title:'"Usage"'},"{\n method: 'POST', // *GET, POST, PUT, DELETE, etc.\n mode: 'cors', // no-cors, *cors, same-origin\n cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached\n credentials: 'same-origin', // include, *same-origin, omit\n headers: {\n 'Content-Type': 'application/json'\n // 'Content-Type': 'application/x-www-form-urlencoded',\n },\n redirect: 'follow', // manual, *follow, error\n referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url\n }\n")),(0,r.kt)("h2",{id:"x"},(0,r.kt)("inlineCode",{parentName:"h2"},"x")),(0,r.kt)("p",null,"Property name of the date, or a function returning a timestamp.",(0,r.kt)("br",{parentName:"p"}),"\n","Instruct the calendar how to extract the ",(0,r.kt)("em",{parentName:"p"},"date")," property from your data."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"x: string | ((datum: DataRecord) => number),\n")),(0,r.kt)("p",null,"You can either pass a:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"string"),": key name of the property holding the date, in your datum object. The date will be parsed using ",(0,r.kt)("a",{parentName:"li",href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date"},(0,r.kt)("inlineCode",{parentName:"a"},"Date.parse")),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"function"),": function taking the datum as argument, and should return a timestamp")),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"If your date is a string (e.g. '2020-01-01T00:00:00'), ensure that its format is ",(0,r.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/ISO_8601"},"ISO 8601")," compliant (",(0,r.kt)("inlineCode",{parentName:"p"},"YYYY-MM-DDTHH:mm:ss.sssZ"),"), or it may lead to inconsistency/precision loss."),(0,r.kt)("p",{parentName:"admonition"},"If possible, we recommend to always use timestamp, to avoid all timezone related issues.")),(0,r.kt)("h4",{id:"example"},"Example"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Extract date using property name"',title:'"Extract',date:!0,using:!0,property:!0,'name"':!0},"// highlight-next-line\nvar data = [{ column1: '2012-01-01', column2: 3 }];\n\ncal.paint({\n // highlight-next-line\n data: { source: data, x: 'column1' },\n});\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Extract date using a custom function"',title:'"Extract',date:!0,using:!0,a:!0,custom:!0,'function"':!0},"// highlight-next-line\nvar data = [{ column1: '2012-01-01', column2: 3 }];\n\ncal.paint({\n data: {\n source: data,\n // highlight-start\n x: datum => {\n return +new Date(datum['column1']);\n },\n // highlight-end\n },\n});\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Compute date from multiple properties"',title:'"Compute',date:!0,from:!0,multiple:!0,'properties"':!0},"// highlight-next-line\nvar data = [{ year: 2020, month: 1, value: 3 }];\n\ncal.paint({\n data: {\n source: data,\n // highlight-start\n x: datum => {\n return +new Date(datum['year'], datum['month'] - 1, 1);\n },\n // highlight-end\n },\n});\n")),(0,r.kt)("h2",{id:"y"},(0,r.kt)("inlineCode",{parentName:"h2"},"y")),(0,r.kt)("p",null,"Property name of the the value, or a function returning the value.",(0,r.kt)("br",{parentName:"p"}),"\n","Instruct the calendar how to extract the ",(0,r.kt)("em",{parentName:"p"},"value")," property from your data."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"y: string | ((datum: DataRecord) => number | string),\n")),(0,r.kt)("p",null,"You can either pass a:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"string"),": key name of the property holding the value, in your datum object. The value should be a number."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"function"),": function taking the datum as argument, and should return the value, as a number or a string")),(0,r.kt)("h4",{id:"example-1"},"Example"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Extract value using property name"',title:'"Extract',value:!0,using:!0,property:!0,'name"':!0},"// highlight-next-line\nvar data = [{ column1: '2012-01-01', column2: 3 }];\n\ncal.paint({\n // highlight-next-line\n data: { source: data, y: 'column2' },\n});\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Extract value using a built-in function"',title:'"Extract',value:!0,using:!0,a:!0,"built-in":!0,'function"':!0},"// highlight-next-line\nvar data = [{ date: '2012-01-01', high: '30', low: '16' }];\n\ncal.paint({\n data: {\n source: data,\n // highlight-start\n y: datum => {\n // You can use the function to pre-process your values\n return +datum['high'] + +datum['low']) / 2;\n },\n // highlight-end\n },\n});\n")),(0,r.kt)("h2",{id:"groupy"},(0,r.kt)("inlineCode",{parentName:"h2"},"groupY")),(0,r.kt)("p",null,"Aggregate function, to group all values from the same subDomain."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"type DataGroupType = 'sum' | 'count' | 'min' | 'max' | 'median';\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"groupY:\n | DataGroupType\n | ((values: (number | string | null)[]) => number | string | null),\n")),(0,r.kt)("p",null,"You can either pass a:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"string"),": name of a built-in aggregate function (see ",(0,r.kt)("em",{parentName:"li"},"DataGroupType"),"), only available if your values are numeric"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"function"),": function taking an array of datum from the same subDomain, and should return a new aggregated value.")),(0,r.kt)("p",null,"Default: ",(0,r.kt)("inlineCode",{parentName:"p"},"sum")),(0,r.kt)("admonition",{type:"caution"},(0,r.kt)("p",{parentName:"admonition"},"If your values are non-numeric, you have to use ",(0,r.kt)("inlineCode",{parentName:"p"},"count"),", or implement your own aggregation strategy")),(0,r.kt)("h4",{id:"example-2"},"Example"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="data.js"',title:'"data.js"'},"var data = [\n { column1: '2012-01-01', column2: 3 },\n { column1: '2012-01-01', column2: 4 },\n { column1: '2012-01-02', column2: 5 },\n];\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Group using a built-in function"',title:'"Group',using:!0,a:!0,"built-in":!0,'function"':!0},"cal.paint({\n data: {\n source: data,\n x: 'column1',\n y: 'column2',\n // highlight-next-line\n groupY: 'sum',\n },\n});\n")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="Group using a custom function"',title:'"Group',using:!0,a:!0,custom:!0,'function"':!0},"cal.paint({\n data: {\n source: data,\n x: 'column1',\n y: 'column2',\n // highlight-start\n groupY: data => {\n // data === [3, 4, 5]\n return data.reduce((a, b) => a + b, 0);\n },\n // highlight-end\n },\n});\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"groupY")," also supports values with non-numeric type, such as"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js",metastring:'title="data.js"',title:'"data.js"'},"var data = [\n { column1: '2012-01-01', column2: 'Asia' },\n { column1: '2012-01-01', column2: 'Europe' },\n { column1: '2012-01-02', column2: 'Asia' },\n];\n")),(0,r.kt)("p",null,"In that case, only the ",(0,r.kt)("inlineCode",{parentName:"p"},"count")," DataGroupType will be available, and you should implement\nyour own ",(0,r.kt)("inlineCode",{parentName:"p"},"groupY")," function if you are grouping your values by another strategy."),(0,r.kt)("h2",{id:"defaultvalue"},(0,r.kt)("inlineCode",{parentName:"h2"},"defaultValue")),(0,r.kt)("p",null,"Default value to use when your dataset does not have a value for a date."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-js"},"defaultValue: null | number | string,\n")),(0,r.kt)("p",null,"Default: ",(0,r.kt)("inlineCode",{parentName:"p"},"null")),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"The most common use case will be to set it to ",(0,r.kt)("inlineCode",{parentName:"p"},"0")),(0,r.kt)("p",{parentName:"admonition"},"This option used to be known as ",(0,r.kt)("inlineCode",{parentName:"p"},"considerMissingDataAsZero")," in the previous versions")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.83ff3895.js b/assets/js/runtime~main.bfc5b81a.js similarity index 67% rename from assets/js/runtime~main.83ff3895.js rename to assets/js/runtime~main.bfc5b81a.js index 1a60039..3a833a1 100644 --- a/assets/js/runtime~main.83ff3895.js +++ b/assets/js/runtime~main.bfc5b81a.js @@ -1 +1 @@ -(()=>{"use strict";var e,a,f,d,t,c={},r={};function b(e){var a=r[e];if(void 0!==a)return a.exports;var f=r[e]={id:e,loaded:!1,exports:{}};return c[e].call(f.exports,f,f.exports,b),f.loaded=!0,f.exports}b.m=c,b.c=r,e=[],b.O=(a,f,d,t)=>{if(!f){var c=1/0;for(i=0;i=t)&&Object.keys(b.O).every((e=>b.O[e](f[o])))?f.splice(o--,1):(r=!1,t0&&e[i-1][2]>t;i--)e[i]=e[i-1];e[i]=[f,d,t]},b.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return b.d(a,{a:a}),a},f=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,b.t=function(e,d){if(1&d&&(e=this(e)),8&d)return e;if("object"==typeof e&&e){if(4&d&&e.__esModule)return e;if(16&d&&"function"==typeof e.then)return e}var t=Object.create(null);b.r(t);var c={};a=a||[null,f({}),f([]),f(f)];for(var r=2&d&&e;"object"==typeof r&&!~a.indexOf(r);r=f(r))Object.getOwnPropertyNames(r).forEach((a=>c[a]=()=>e[a]));return c.default=()=>e,b.d(t,c),t},b.d=(e,a)=>{for(var f in a)b.o(a,f)&&!b.o(e,f)&&Object.defineProperty(e,f,{enumerable:!0,get:a[f]})},b.f={},b.e=e=>Promise.all(Object.keys(b.f).reduce(((a,f)=>(b.f[f](e,a),a)),[])),b.u=e=>"assets/js/"+({53:"935f2afb",152:"54f44165",225:"3152febb",530:"02335ff3",708:"e53684a9",836:"0480b142",905:"d74e087b",1141:"d700bc26",1156:"1887ed91",1577:"8e45d32c",1925:"9f1f940a",2620:"291b3faf",2857:"d4378dd0",3039:"fbd7a87c",3237:"1df93b7f",3238:"9a787a50",3267:"1b44e66a",3530:"bc0c115d",3543:"63f7707f",3647:"45f95ab0",3680:"cf38f87c",4268:"fcd8680e",4353:"f36d3bf6",4623:"acb3dc87",4866:"6db0139d",4951:"269806c1",5321:"adbb5675",5449:"4c448d85",5504:"ede31def",5930:"70309ba1",6292:"94d84e32",6316:"27d9d47d",6378:"fd9a214d",6441:"a7fac609",7492:"0f1d9834",7646:"87004880",7657:"99f49855",7670:"c563ecd9",7808:"05f8f68c",7918:"17896441",7920:"1a4e3797",9122:"0f2fc009",9291:"7ddc878a",9443:"a55e2228",9454:"11efeae8",9514:"1be78505",9817:"14eb3368",9961:"2a64fe00",9984:"5c20b834"}[e]||e)+"."+{53:"545fd232",152:"56ebe8f0",225:"8914fa92",530:"a01278ed",708:"df80352d",836:"7380082e",905:"3468bfed",1141:"351b9a4d",1156:"f636b384",1577:"f58ba47d",1925:"4a19c18c",2620:"44da4edf",2857:"14e3d4f8",3039:"3682e3d3",3237:"b58f5303",3238:"2e30b632",3267:"9632a579",3530:"39ff218f",3543:"7e885d3e",3647:"f44060dc",3680:"fc49bb71",4268:"d7c8bf27",4353:"a5e38992",4623:"57bf4db8",4866:"6092fc69",4951:"3d4c773c",4972:"ad604608",5321:"f9c45b54",5449:"f308a995",5504:"f3772bc0",5930:"3d1f350b",6292:"64de07fc",6316:"eb8025db",6378:"54b3b07b",6441:"e0752c9d",6780:"57d7ee67",6945:"d1d76cc9",7492:"c92b262a",7646:"922107e6",7657:"197ab996",7670:"eb2cfd6e",7808:"7f731f1d",7918:"4276c16b",7920:"ff62fad4",8894:"cf808ebc",9122:"e4e9daac",9291:"fbe7a401",9443:"71ec4801",9454:"699eee1c",9514:"a617911c",9817:"5816b314",9961:"af4d5ba1",9984:"b82ca236"}[e]+".js",b.miniCssF=e=>{},b.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),b.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),d={},t="cal-heatmap-doc:",b.l=(e,a,f,c)=>{if(d[e])d[e].push(a);else{var r,o;if(void 0!==f)for(var n=document.getElementsByTagName("script"),i=0;i{r.onerror=r.onload=null,clearTimeout(s);var t=d[e];if(delete d[e],r.parentNode&&r.parentNode.removeChild(r),t&&t.forEach((e=>e(f))),a)return a(f)},s=setTimeout(u.bind(null,void 0,{type:"timeout",target:r}),12e4);r.onerror=u.bind(null,r.onerror),r.onload=u.bind(null,r.onload),o&&document.head.appendChild(r)}},b.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},b.p="/",b.gca=function(e){return e={17896441:"7918",87004880:"7646","935f2afb":"53","54f44165":"152","3152febb":"225","02335ff3":"530",e53684a9:"708","0480b142":"836",d74e087b:"905",d700bc26:"1141","1887ed91":"1156","8e45d32c":"1577","9f1f940a":"1925","291b3faf":"2620",d4378dd0:"2857",fbd7a87c:"3039","1df93b7f":"3237","9a787a50":"3238","1b44e66a":"3267",bc0c115d:"3530","63f7707f":"3543","45f95ab0":"3647",cf38f87c:"3680",fcd8680e:"4268",f36d3bf6:"4353",acb3dc87:"4623","6db0139d":"4866","269806c1":"4951",adbb5675:"5321","4c448d85":"5449",ede31def:"5504","70309ba1":"5930","94d84e32":"6292","27d9d47d":"6316",fd9a214d:"6378",a7fac609:"6441","0f1d9834":"7492","99f49855":"7657",c563ecd9:"7670","05f8f68c":"7808","1a4e3797":"7920","0f2fc009":"9122","7ddc878a":"9291",a55e2228:"9443","11efeae8":"9454","1be78505":"9514","14eb3368":"9817","2a64fe00":"9961","5c20b834":"9984"}[e]||e,b.p+b.u(e)},(()=>{var e={1303:0,532:0};b.f.j=(a,f)=>{var d=b.o(e,a)?e[a]:void 0;if(0!==d)if(d)f.push(d[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var t=new Promise(((f,t)=>d=e[a]=[f,t]));f.push(d[2]=t);var c=b.p+b.u(a),r=new Error;b.l(c,(f=>{if(b.o(e,a)&&(0!==(d=e[a])&&(e[a]=void 0),d)){var t=f&&("load"===f.type?"missing":f.type),c=f&&f.target&&f.target.src;r.message="Loading chunk "+a+" failed.\n("+t+": "+c+")",r.name="ChunkLoadError",r.type=t,r.request=c,d[1](r)}}),"chunk-"+a,a)}},b.O.j=a=>0===e[a];var a=(a,f)=>{var d,t,c=f[0],r=f[1],o=f[2],n=0;if(c.some((a=>0!==e[a]))){for(d in r)b.o(r,d)&&(b.m[d]=r[d]);if(o)var i=o(b)}for(a&&a(f);n{"use strict";var e,a,f,d,t,r={},c={};function b(e){var a=c[e];if(void 0!==a)return a.exports;var f=c[e]={id:e,loaded:!1,exports:{}};return r[e].call(f.exports,f,f.exports,b),f.loaded=!0,f.exports}b.m=r,b.c=c,e=[],b.O=(a,f,d,t)=>{if(!f){var r=1/0;for(i=0;i=t)&&Object.keys(b.O).every((e=>b.O[e](f[o])))?f.splice(o--,1):(c=!1,t0&&e[i-1][2]>t;i--)e[i]=e[i-1];e[i]=[f,d,t]},b.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return b.d(a,{a:a}),a},f=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,b.t=function(e,d){if(1&d&&(e=this(e)),8&d)return e;if("object"==typeof e&&e){if(4&d&&e.__esModule)return e;if(16&d&&"function"==typeof e.then)return e}var t=Object.create(null);b.r(t);var r={};a=a||[null,f({}),f([]),f(f)];for(var c=2&d&&e;"object"==typeof c&&!~a.indexOf(c);c=f(c))Object.getOwnPropertyNames(c).forEach((a=>r[a]=()=>e[a]));return r.default=()=>e,b.d(t,r),t},b.d=(e,a)=>{for(var f in a)b.o(a,f)&&!b.o(e,f)&&Object.defineProperty(e,f,{enumerable:!0,get:a[f]})},b.f={},b.e=e=>Promise.all(Object.keys(b.f).reduce(((a,f)=>(b.f[f](e,a),a)),[])),b.u=e=>"assets/js/"+({53:"935f2afb",152:"54f44165",225:"3152febb",530:"02335ff3",708:"e53684a9",836:"0480b142",905:"d74e087b",1141:"d700bc26",1156:"1887ed91",1577:"8e45d32c",1925:"9f1f940a",2620:"291b3faf",2857:"d4378dd0",3039:"fbd7a87c",3237:"1df93b7f",3238:"9a787a50",3267:"1b44e66a",3530:"bc0c115d",3543:"63f7707f",3647:"45f95ab0",3680:"cf38f87c",4268:"fcd8680e",4353:"f36d3bf6",4623:"acb3dc87",4866:"6db0139d",4951:"269806c1",5321:"adbb5675",5449:"4c448d85",5504:"ede31def",5930:"70309ba1",6292:"94d84e32",6316:"27d9d47d",6378:"fd9a214d",6441:"a7fac609",7492:"0f1d9834",7646:"87004880",7657:"99f49855",7670:"c563ecd9",7808:"05f8f68c",7918:"17896441",7920:"1a4e3797",9122:"0f2fc009",9291:"7ddc878a",9443:"a55e2228",9454:"11efeae8",9514:"1be78505",9817:"14eb3368",9961:"2a64fe00",9984:"5c20b834"}[e]||e)+"."+{53:"545fd232",152:"56ebe8f0",225:"8914fa92",530:"a01278ed",708:"df80352d",836:"7380082e",905:"3468bfed",1141:"351b9a4d",1156:"f636b384",1577:"f58ba47d",1925:"4a19c18c",2620:"44da4edf",2857:"14e3d4f8",3039:"3682e3d3",3237:"b58f5303",3238:"2e30b632",3267:"9632a579",3530:"39ff218f",3543:"7e885d3e",3647:"f44060dc",3680:"23bc6694",4268:"d7c8bf27",4353:"a5e38992",4623:"57bf4db8",4866:"6092fc69",4951:"3d4c773c",4972:"ad604608",5321:"f9c45b54",5449:"f308a995",5504:"f3772bc0",5930:"3d1f350b",6292:"64de07fc",6316:"eb8025db",6378:"54b3b07b",6441:"e0752c9d",6780:"57d7ee67",6945:"d1d76cc9",7492:"c92b262a",7646:"922107e6",7657:"197ab996",7670:"eb2cfd6e",7808:"7f731f1d",7918:"4276c16b",7920:"ff62fad4",8894:"cf808ebc",9122:"e4e9daac",9291:"fbe7a401",9443:"71ec4801",9454:"699eee1c",9514:"a617911c",9817:"5816b314",9961:"af4d5ba1",9984:"b82ca236"}[e]+".js",b.miniCssF=e=>{},b.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),b.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),d={},t="cal-heatmap-doc:",b.l=(e,a,f,r)=>{if(d[e])d[e].push(a);else{var c,o;if(void 0!==f)for(var n=document.getElementsByTagName("script"),i=0;i{c.onerror=c.onload=null,clearTimeout(s);var t=d[e];if(delete d[e],c.parentNode&&c.parentNode.removeChild(c),t&&t.forEach((e=>e(f))),a)return a(f)},s=setTimeout(u.bind(null,void 0,{type:"timeout",target:c}),12e4);c.onerror=u.bind(null,c.onerror),c.onload=u.bind(null,c.onload),o&&document.head.appendChild(c)}},b.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},b.p="/",b.gca=function(e){return e={17896441:"7918",87004880:"7646","935f2afb":"53","54f44165":"152","3152febb":"225","02335ff3":"530",e53684a9:"708","0480b142":"836",d74e087b:"905",d700bc26:"1141","1887ed91":"1156","8e45d32c":"1577","9f1f940a":"1925","291b3faf":"2620",d4378dd0:"2857",fbd7a87c:"3039","1df93b7f":"3237","9a787a50":"3238","1b44e66a":"3267",bc0c115d:"3530","63f7707f":"3543","45f95ab0":"3647",cf38f87c:"3680",fcd8680e:"4268",f36d3bf6:"4353",acb3dc87:"4623","6db0139d":"4866","269806c1":"4951",adbb5675:"5321","4c448d85":"5449",ede31def:"5504","70309ba1":"5930","94d84e32":"6292","27d9d47d":"6316",fd9a214d:"6378",a7fac609:"6441","0f1d9834":"7492","99f49855":"7657",c563ecd9:"7670","05f8f68c":"7808","1a4e3797":"7920","0f2fc009":"9122","7ddc878a":"9291",a55e2228:"9443","11efeae8":"9454","1be78505":"9514","14eb3368":"9817","2a64fe00":"9961","5c20b834":"9984"}[e]||e,b.p+b.u(e)},(()=>{var e={1303:0,532:0};b.f.j=(a,f)=>{var d=b.o(e,a)?e[a]:void 0;if(0!==d)if(d)f.push(d[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var t=new Promise(((f,t)=>d=e[a]=[f,t]));f.push(d[2]=t);var r=b.p+b.u(a),c=new Error;b.l(r,(f=>{if(b.o(e,a)&&(0!==(d=e[a])&&(e[a]=void 0),d)){var t=f&&("load"===f.type?"missing":f.type),r=f&&f.target&&f.target.src;c.message="Loading chunk "+a+" failed.\n("+t+": "+r+")",c.name="ChunkLoadError",c.type=t,c.request=r,d[1](c)}}),"chunk-"+a,a)}},b.O.j=a=>0===e[a];var a=(a,f)=>{var d,t,r=f[0],c=f[1],o=f[2],n=0;if(r.some((a=>0!==e[a]))){for(d in c)b.o(c,d)&&(b.m[d]=c[d]);if(o)var i=o(b)}for(a&&a(f);n - + - + \ No newline at end of file diff --git a/docs/API/addTemplates.html b/docs/API/addTemplates.html index 2eaba67..8b4463d 100644 --- a/docs/API/addTemplates.html +++ b/docs/API/addTemplates.html @@ -13,13 +13,13 @@ - +

addTemplates()

Add a new subDomain template

addTemplates(Template[] | Template): void;

Arguments

Return

  • void
caution

This method have to be called before paint().

What is a template?

See the Templates section for more informations.


Usage

// Create a template
// Content skipped, see the Templates section for full template example
const quarterTemplate = () => {};

const cal = new CalHeatmap();
// Add the template
cal.addTemplates(quarterTemplate);

cal.paint({
range: 2,
domain: { type: 'year', gutter: 10, label: { textAlign: 'start' } },
subDomain: {
// Use the template
type: 'quarter',
width: 60,
height: 15,
label: '[Quarter] Q',
radius: 3,
},
});
- + \ No newline at end of file diff --git a/docs/API/destroy.html b/docs/API/destroy.html index c9045be..3301dc4 100644 --- a/docs/API/destroy.html +++ b/docs/API/destroy.html @@ -13,13 +13,13 @@ - +

destroy()

Destroy the calendar

const cal = new CalHeatmap();
cal.destroy(): Promise<unknown>

Arguments

  • none

Return

  • Return a Promise, which will resolve once the calendar finished destroying (after all animations completed).

Usage

const cal = new CalHeatmap();
cal.paint({ ... });

// Destroy it
cal.destroy().then(() => { console.log('Destroy complete!') });
tip

There's a destroy event, triggered at the start of the destroy process.

- + \ No newline at end of file diff --git a/docs/API/dimensions.html b/docs/API/dimensions.html index 211da69..28678ec 100644 --- a/docs/API/dimensions.html +++ b/docs/API/dimensions.html @@ -13,13 +13,13 @@ - +

dimensions()

Return the calendar's dimensions

type Dimensions = {
width: number,
height: number,
};

const cal = new CalHeatmap();
cal.dimensions(): Dimensions;

Arguments

  • none

Return

  • An object, with the calendar width and height in pixels.
tip

You can also retrieve the calendar's dimensions with the resize event.

Usage

const cal = new CalHeatmap();
cal.paint().then(() => {
// Wait for paint() to complete before retrieving the dimensions
cal.dimensions(); // { width: 969, height: 142 }
});
- + \ No newline at end of file diff --git a/docs/API/extendDayjs.html b/docs/API/extendDayjs.html index fa99933..a4ad5ee 100644 --- a/docs/API/extendDayjs.html +++ b/docs/API/extendDayjs.html @@ -13,14 +13,14 @@ - +

extendDayjs()

Extend the dayjs library with plugins

const cal = new CalHeatmap();
cal.extend(PluginFunc);

The built-in dayjs is already shipped with some plugins, see the DateHelper for the list of plugins.

Arguments

Return

  • void

Usage

Example with the BuddhistEra plugin

Inject the dayjs plugin in your page <head>

index.html
<script src="https://cdn.jsdelivr.net/npm/dayjs@1/plugin/buddhistEra.js"></script>

Extend dayjs with the plugin, before the paint() call

index.js
const cal = new CalHeatmap();
cal.extendDayjs(window.dayjs_plugin_buddhistEra);
cal.paint();
- + \ No newline at end of file diff --git a/docs/API/fill.html b/docs/API/fill.html index a446b5e..1e01215 100644 --- a/docs/API/fill.html +++ b/docs/API/fill.html @@ -13,7 +13,7 @@ - + @@ -21,7 +21,7 @@

fill()

Update the calendar's data set

const cal = new CalHeatmap();
cal.fill(data: DataOptions['source']): Promise<unknown>;

Arguments

Return

  • A Promise, that will resolve once the calendar is filled with the new data.

When to use

Use this method if you only want to update your calendar dataset, without trigerring any other changes, as fill() is already called behind the scene by paint() and all navigation methods.

Usage

const cal = new CalHeatmap();
cal.paint({ data: { source: 'https://my-api.com/weather-min-temp.json' } });
// User opted to show max temp instead of min temp
cal.fill('https://my-api.com/weather-max-temp.json');
- + \ No newline at end of file diff --git a/docs/API/navigation.html b/docs/API/navigation.html index 96ced8e..caf6b77 100644 --- a/docs/API/navigation.html +++ b/docs/API/navigation.html @@ -13,7 +13,7 @@ - + @@ -21,7 +21,7 @@
- + \ No newline at end of file diff --git a/docs/API/navigation/jumpTo.html b/docs/API/navigation/jumpTo.html index f1bc6ba..85c3f8e 100644 --- a/docs/API/navigation/jumpTo.html +++ b/docs/API/navigation/jumpTo.html @@ -13,13 +13,13 @@ - +

jumpTo()

Scroll the calendar to the given date.

cal.jumpTo(date: Date, reset: boolean): Promise<unknown>

Arguments:

  • date: a Date object, representing the date to jump to.
  • reset: whether if the given date should be at the start of the calendar. Default false

Return:

  • A Promise, that will resolve once all the new domains have loaded, and filled with data.
- + \ No newline at end of file diff --git a/docs/API/navigation/next.html b/docs/API/navigation/next.html index 2261b53..10e4e38 100644 --- a/docs/API/navigation/next.html +++ b/docs/API/navigation/next.html @@ -13,13 +13,13 @@ - +

next()

Shift the calendar by the given number of domains forward (in the future).

cal.next(steps?: number): Promise<unknown>

Arguments:

  • steps: the number of domains to shift, default 1

Return:

  • A Promise, that will resolve once all the new domains have loaded, and filled with data.
- + \ No newline at end of file diff --git a/docs/API/navigation/previous.html b/docs/API/navigation/previous.html index c60ad35..366a520 100644 --- a/docs/API/navigation/previous.html +++ b/docs/API/navigation/previous.html @@ -13,13 +13,13 @@ - +

previous()

Shift the calendar by the given number of domains backward (in the past).

cal.previous(steps?: number): Promise<unknown>

Arguments:

  • steps: the number of domains to shift, default 1

Return:

  • A Promise, that will resolve once all the new domains have loaded, and filled with data.
- + \ No newline at end of file diff --git a/docs/API/paint.html b/docs/API/paint.html index 24a7659..cd0acf4 100644 --- a/docs/API/paint.html +++ b/docs/API/paint.html @@ -13,13 +13,13 @@ - +

paint()

Paint the calendar using the given Options and Plugins.

const cal = new CalHeatmap();
cal.paint(options: Options, plugins? PluginDefinition[] | PluginDefinition): Promise<unknown>;

This is the core method, used to setup and paint the calendar.

Arguments

Return

  • A Promise, that will resolve once the calendar is painted, and filled with data.
tip

The calendar can be updated dynamically by calling this method with new Options.


Usage

With custom options
const cal = new CalHeatmap();
cal.paint({
range: 1,
date: { start: new Date(2020, 0, 1) },
});
With plugins
const cal = new CalHeatmap();
cal.paint({}, [[Timezone, { timezone: 'Europe/Paris' }]]);
- + \ No newline at end of file diff --git a/docs/advanced.html b/docs/advanced.html index 3b0eacb..1b93751 100644 --- a/docs/advanced.html +++ b/docs/advanced.html @@ -13,13 +13,13 @@ - + - + \ No newline at end of file diff --git a/docs/advanced/scaleType.html b/docs/advanced/scaleType.html index 3565afd..0a4d12f 100644 --- a/docs/advanced/scaleType.html +++ b/docs/advanced/scaleType.html @@ -13,7 +13,7 @@ - + @@ -412,7 +412,7 @@ } }
Result
Loading...

There are also variant of the diverging scale:

  • diverging-log - like log, but with a pivot that defaults to 1; defaults to the RdBu scheme
  • diverging-pow - like pow, but with a pivot; defaults to the RdBu scheme
  • diverging-sqrt - like sqrt, but with a pivot; defaults to the RdBu scheme
  • diverging-symlog - like symlog, but with a pivot; defaults to the RdBu scheme
- + \ No newline at end of file diff --git a/docs/category/getting-started.html b/docs/category/getting-started.html index b0f63a9..5828a06 100644 --- a/docs/category/getting-started.html +++ b/docs/category/getting-started.html @@ -13,13 +13,13 @@ - + - + \ No newline at end of file diff --git a/docs/events.html b/docs/events.html index 183f51e..420c867 100644 --- a/docs/events.html +++ b/docs/events.html @@ -13,7 +13,7 @@ - + @@ -23,7 +23,7 @@ Used to exit the calendar from the maxDateReached status.

Arguments: none

Usage example
cal.on('maxDateNotReached', () => {
// Do something to enable back the NEXT button,
// after disabling it with the maxDateReached event
});

destroy

Event emitted when calling destroy().

Arguments: none

caution

This event is emitted at the start of the destroy process, use the promise returned by destroy() if you want to wait for the destroy process to complete.

Usage example
cal.on('destroy', () => {
// Calendar has started destroying
// Do something
});
- + \ No newline at end of file diff --git a/docs/faq.html b/docs/faq.html index 8713f43..9e6cb01 100644 --- a/docs/faq.html +++ b/docs/faq.html @@ -13,7 +13,7 @@ - + @@ -23,7 +23,7 @@ function is provided, so you can customize the displayed text.

Dark/Light mode support

Use the theme option

Trigger an action when clicking a calendar cell

See the click event

Use a custom subDomain interval, such as 6 hours, 15 min, etc ...

See Templates, to create your own custom subDomain with your desired time interval

Refresh the calendar with new data, dynamically

See fill API

How to change the domain/subDomain label text size/font

Take a look at the css

  • domain label are controlled via .ch-domain-text
  • subDomain text are controlled via .ch-subdomain-text

Show only weekdays, instead of all days of the week

Use a custom template. You can see an example here

Use a data source, behind authentication

data.source is expecting a string url. When your API is behind authentication, or required additional request headers, you can use requestinit to customize the http request, to add addition headers, change the request type to POST, etc ...

Right to Left (RTL) support

Set both domain.sort and subDomain.sort to desc

Reproduce a calendar in the Github contribution style

See Github showcase

Does it work with React ?

Yes, see this starter demo

The homepage demo is also a React Component, see the source code directly on the documention repo

Does it work with VueJS ?

Yes, see this starter demo

Does it work on NodeJS ?

The script requires a DOM Element. As long as your app have a virtual DOM Element, it should work.

- + \ No newline at end of file diff --git a/docs/getting-started/browser-support.html b/docs/getting-started/browser-support.html index b11c3ae..00fe4ac 100644 --- a/docs/getting-started/browser-support.html +++ b/docs/getting-started/browser-support.html @@ -13,13 +13,13 @@ - +

Browser support

Cal-Heatmap support more than 90% of the global audience, with the following browserlist config

last 2 versions, not dead, > 0.2%

Cal-Heatmap is tested against the following browsers, using real browsers/devices via Browserstack

Desktop

  • Google Chrome 95+
  • Mozilla Firefox 95+
  • Microsoft Edge 95+
  • Safari 14.1+

Mobile

  • Google Chrome Android 7+
  • Samsung Internet Android 7+
  • Safari iOS 14+
- + \ No newline at end of file diff --git a/docs/getting-started/installation.html b/docs/getting-started/installation.html index 046fe2c..b5d3662 100644 --- a/docs/getting-started/installation.html +++ b/docs/getting-started/installation.html @@ -13,13 +13,13 @@ - +

Installation

Install

Install the dependencies in your page <head>.

<script src="https://d3js.org/d3.v7.min.js"></script>
<!-- v6 is also supported -->
<script src="https://d3js.org/d3.v6.min.js"></script>

Install the library in your page <head>.

<script src="https://unpkg.com/cal-heatmap/dist/cal-heatmap.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/cal-heatmap/dist/cal-heatmap.css">

Distribution target

Cal-Heatmap is distributed in 2 different file formats.

  • esm (works with import syntax — recommended)
  • umd (works with <script> tags or RequireJS)

Each file formats is also shipped in regular and minified/compressed version with Terser.

The bundle files are located in the dist folder, and code source in src.

cal-heatmap
├── dist
│ ├── cal-heatmap.js
│ ├── cal-heatmap.min.js
│ ├── cal-heatmap.esm.js
│ └── cal-heatmap.min.esm.js
│ └── cal-heatmap.css
│ ├── plugins
│ │ └── Legend.js
│ │ └── Legend.min.js
│ │ └── Legend.esm.js
│ │ └── Legend.min.esm.js
│ │ └── Tooltip.js
│ │ └── Tooltip.min.js
│ │ └── Tooltip.esm.js
│ │ └── Tooltip.min.esm.js
├── src
│ ├── cal-heatmap.js
│ ├── ....

- + \ No newline at end of file diff --git a/docs/getting-started/quickstart.html b/docs/getting-started/quickstart.html index f481a7e..af00329 100644 --- a/docs/getting-started/quickstart.html +++ b/docs/getting-started/quickstart.html @@ -13,7 +13,7 @@ - + @@ -48,7 +48,7 @@ }
Result
Loading...
note

You can customize the calendar by passing an Options object and/or a Plugins list to paint().

tip

See the showcase section for more examples.

- + \ No newline at end of file diff --git a/docs/getting-started/typescript.html b/docs/getting-started/typescript.html index 1748143..3a13ca2 100644 --- a/docs/getting-started/typescript.html +++ b/docs/getting-started/typescript.html @@ -13,13 +13,13 @@ - +

Typescript

Cal-Heatmap ships with official type declarations for TypeScript in NPM package out of the box.

danger

Typescript declaration files are still work in progress, and may change in the future

Install via NPM

npm install cal-heatmap

Import and use in your Typescript file

import CalHeatmap from 'cal-heatmap';
const cal: CalHeatmap = new CalHeatmap();
- + \ No newline at end of file diff --git a/docs/migrate_from_v3.html b/docs/migrate_from_v3.html index 8cdf634..30b7a6b 100644 --- a/docs/migrate_from_v3.html +++ b/docs/migrate_from_v3.html @@ -13,7 +13,7 @@ - + @@ -32,7 +32,7 @@ Old subDomain option has been moved to subDomain.type

cellSize

Moved to subDomain.width and subDomain.height

cellRadius

Moved to subDomain.radius

cellPadding

Moved to subDomain.gutter

subDomainTextFormat

Moved to subDomain.label

Removed settings

weekStartOnMonday

Use a custom date.locale, or a custom Template.

legend, displayLegend, legendCellSize, legendCellPadding, legendCellMargin, legendVerticalPosition, legendHorizontalPosition, legendOrientation, legendTitleFormat

Removed, migrated to Legend plugin

legendColors

Moved to a new option inside scale.

subDomainDateFormat, subDomainTitleFormat, itemName

Removed, use Tooltip text

tooltip

Removed, migrated to Tooltip plugin.

afterLoadData

CalHeatmap is not expecting a strict opinionated data structure anymore, and accept an array of object, just like d3.js. See data.x, data.y and data.groupY

colLimit, rowLimit

To customize the layout of the subDomains, a new Template system has been introduced

nextSelector, previousSelector

The same objective can be achieved by adding an onClick() event on your desired DOM Element, and call next() or previous() on the calendar instance.

considerMissingDataAsZero

Data are treated as they are, you can preprocess/transform them using data.y and data,.groupY options.

itemNamespace

Obsolete, was only used internally to namespace the nextSelector and previousSelector onclick events.

New methods

  • on(eventName, callback) has been added, to replace all old callback functions.

See Events for the complete list of events

afterLoad and onComplete removed

These events are now obsolete, as all methods now return a promise.

Renamed methods

  • init(options) renamed to paint(options). This method can now be called multiple times with new options, and will update the calendar dynamically, instead of redrawing it from scratch.
  • update(data, afterLoad, updateMode) renamed to fill(data), to reflect that it's for updating data only, and not the options. It now accepts only data as its only argument, all other arguments can be set via paint()
  • destroy(callback) do not take a callback argument anymore, and returns a Promise.

Removed methods

rewind()

The same objective can be achieved by calling jumpTo() with your initial start date on the calendar instance.

showLegend(), removeLegend(), setLegend()

The same objective can be achieved by calling paint({}, [[Legend, LEGEND_OPTIONS]]) on the calendar instance.

highlight

The same objective can be achieved by calling paint({ date: { highlight: [YOUR_DATES] } }) on the calendar instance.

getSVG

Delegated to a plugin

Over changes

  • All the CSS classes used for data coloring have been removed. The scale option allow a more precise color customization.
  • All the x_ subDomains variants aside from x_day have been removed. You can re-created them with a custom template.
  • The mouse cursor do not change to pointer when hovering on a subDomain cell automatically when there is an onClick event registered, since there is no reliable way to detect if an onClick listener is registered anymore.
  • Test suite migrated to Jest, and start testing on browserstack against a matrix of browsers.
- + \ No newline at end of file diff --git a/docs/options.html b/docs/options.html index 0843a11..ac9b7a8 100644 --- a/docs/options.html +++ b/docs/options.html @@ -13,7 +13,7 @@ - + @@ -50,7 +50,7 @@ }
Result
Loading...

These are live editor: you can edit the code inline, and see the result in live.

Use them to test settings, and see what happen.

- + \ No newline at end of file diff --git a/docs/options/animationDuration.html b/docs/options/animationDuration.html index 1176ca7..33be9b0 100644 --- a/docs/options/animationDuration.html +++ b/docs/options/animationDuration.html @@ -13,14 +13,14 @@ - +

animationDuration

Control the duration of the various animations

animationDuration: number, // duration, in milliseconds

Default: 200

Animation is used each time there is a change in the calendar UI, such as navigation, resize, etc...


Usage

const cal = new CalHeatmap();
cal.paint({ animationDuration: 500 });
- + \ No newline at end of file diff --git a/docs/options/data.html b/docs/options/data.html index 380b097..0ec19f0 100644 --- a/docs/options/data.html +++ b/docs/options/data.html @@ -13,12 +13,12 @@ - +
-

data

Specify how to fetch and process the data used to fill the calendar

type DataRecord = Record<string, string | number>;
type DataGroupType = 'sum' | 'count' | 'min' | 'max' | 'median';

type DataOptions = {
source: string | DataRecord[],
type: 'json' | 'csv' | 'tsv' | 'txt',
requestInit: object,
x: string | ((datum: DataRecord) => number),
y: string | ((datum: DataRecord) => number),
groupY:
| DataGroupType
| ((values: (number | string | null)[]) => number | string | null),
defaultValue: null | number | string,
};

The calendar is expecting an array of objects as input.
+

data

Specify how to fetch and process the data used to fill the calendar

type DataRecord = Record<string, string | number>;
type DataGroupType = 'sum' | 'count' | 'min' | 'max' | 'average';

type DataOptions = {
source: string | DataRecord[],
type: 'json' | 'csv' | 'tsv' | 'txt',
requestInit: object,
x: string | ((datum: DataRecord) => number),
y: string | ((datum: DataRecord) => number),
groupY:
| DataGroupType
| ((values: (number | string | null)[]) => number | string | null),
defaultValue: null | number | string,
};

The calendar is expecting an array of objects as input.
There is no expected pre-defined structure for the object, but it must at least have one or more property for the date, and another one for the value, which is usually a number, but string is also accepted

Classic object
[
{ date: '2012-01-01', value: 3 },
{ date: '2012-01-02', value: 6 },
...
];
Using timestamp
[
{ t: 1673388319933, p: 3, v: 'Asia' },
{ t: 1673388319934, p: 6, v: 'Europe' },
...
];
Using multiple properties to define a date
[
{ year: 2020, month: 1, day: 1, temperature: 38 },
...
];

More options are available below to instruct the calendar on @@ -28,9 +28,9 @@ customization, see requestInit.

caution

Fetch is used under the hood to load the remote resource. Ensure that your endpoint has CORS setup properly.

type

Parser used to interpret the data returned by your url source.

type: 'json' | 'csv' | 'tsv' | 'txt',

The parser will interpret the data, and convert it to an array of DataRecord.

Default: json

note

This option is used only when the source is an url.

requestInit

Additional requestInit options, send along your data request.

d3-fetch is used under the hood to handle all network requests. See their documentation for further information and usage.

Default: {}

note

This option is used only when the source is an url.

Usage
{
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
}

x

Property name of the date, or a function returning a timestamp.
Instruct the calendar how to extract the date property from your data.

x: string | ((datum: DataRecord) => number),

You can either pass a:

  • string: key name of the property holding the date, in your datum object. The date will be parsed using Date.parse.
  • function: function taking the datum as argument, and should return a timestamp
caution

If your date is a string (e.g. '2020-01-01T00:00:00'), ensure that its format is ISO 8601 compliant (YYYY-MM-DDTHH:mm:ss.sssZ), or it may lead to inconsistency/precision loss.

If possible, we recommend to always use timestamp, to avoid all timezone related issues.

Example

Extract date using property name
var data = [{ column1: '2012-01-01', column2: 3 }];

cal.paint({
data: { source: data, x: 'column1' },
});
Extract date using a custom function
var data = [{ column1: '2012-01-01', column2: 3 }];

cal.paint({
data: {
source: data,
x: datum => {
return +new Date(datum['column1']);
},
},
});
Compute date from multiple properties
var data = [{ year: 2020, month: 1, value: 3 }];

cal.paint({
data: {
source: data,
x: datum => {
return +new Date(datum['year'], datum['month'] - 1, 1);
},
},
});

y

Property name of the the value, or a function returning the value.
-Instruct the calendar how to extract the value property from your data.

y: string | ((datum: DataRecord) => number | string),

You can either pass a:

  • string: key name of the property holding the value, in your datum object. The value should be a number.
  • function: function taking the datum as argument, and should return the value, as a number or a string

Example

Extract value using property name
var data = [{ column1: '2012-01-01', column2: 3 }];

cal.paint({
data: { source: data, y: 'column2' },
});
Extract value using a built-in function
var data = [{ date: '2012-01-01', high: '30', low: '16' }];

cal.paint({
data: {
source: data,
y: datum => {
// You can use the function to pre-process your values
return +datum['high'] + +datum['low']) / 2;
},
},
});

groupY

Aggregate function, to group all values from the same subDomain.

type DataGroupType = 'sum' | 'count' | 'min' | 'max' | 'median';
groupY:
| DataGroupType
| ((values: (number | string | null)[]) => number | string | null),

You can either pass a:

  • string: name of a built-in aggregate function (see DataGroupType), only available if your values are numeric
  • function: function taking an array of datum from the same subDomain, and should return a new aggregated value.

Default: sum

caution

If your values are non-numeric, you have to use count, or implement your own aggregation strategy

Example

data.js
var data = [
{ column1: '2012-01-01', column2: 3 },
{ column1: '2012-01-01', column2: 4 },
{ column1: '2012-01-02', column2: 5 },
];
Group using a built-in function
cal.paint({
data: {
source: data,
x: 'column1',
y: 'column2',
groupY: 'sum',
},
});
Group using a custom function
cal.paint({
data: {
source: data,
x: 'column1',
y: 'column2',
groupY: data => {
// data === [3, 4, 5]
return data.reduce((a, b) => a + b, 0);
},
},
});

groupY also supports values with non-numeric type, such as

data.js
var data = [
{ column1: '2012-01-01', column2: 'Asia' },
{ column1: '2012-01-01', column2: 'Europe' },
{ column1: '2012-01-02', column2: 'Asia' },
];

In that case, only the count DataGroupType will be available, and you should implement +Instruct the calendar how to extract the value property from your data.

y: string | ((datum: DataRecord) => number | string),

You can either pass a:

  • string: key name of the property holding the value, in your datum object. The value should be a number.
  • function: function taking the datum as argument, and should return the value, as a number or a string

Example

Extract value using property name
var data = [{ column1: '2012-01-01', column2: 3 }];

cal.paint({
data: { source: data, y: 'column2' },
});
Extract value using a built-in function
var data = [{ date: '2012-01-01', high: '30', low: '16' }];

cal.paint({
data: {
source: data,
y: datum => {
// You can use the function to pre-process your values
return +datum['high'] + +datum['low']) / 2;
},
},
});

groupY

Aggregate function, to group all values from the same subDomain.

type DataGroupType = 'sum' | 'count' | 'min' | 'max' | 'average';
groupY:
| DataGroupType
| ((values: (number | string | null)[]) => number | string | null),

You can either pass a:

  • string: name of a built-in aggregate function (see DataGroupType), only available if your values are numeric
  • function: function taking an array of datum from the same subDomain, and should return a new aggregated value.

Default: sum

caution

If your values are non-numeric, you have to use count, or implement your own aggregation strategy

Example

data.js
var data = [
{ column1: '2012-01-01', column2: 3 },
{ column1: '2012-01-01', column2: 4 },
{ column1: '2012-01-02', column2: 5 },
];
Group using a built-in function
cal.paint({
data: {
source: data,
x: 'column1',
y: 'column2',
groupY: 'sum',
},
});
Group using a custom function
cal.paint({
data: {
source: data,
x: 'column1',
y: 'column2',
groupY: data => {
// data === [3, 4, 5]
return data.reduce((a, b) => a + b, 0);
},
},
});

groupY also supports values with non-numeric type, such as

data.js
var data = [
{ column1: '2012-01-01', column2: 'Asia' },
{ column1: '2012-01-01', column2: 'Europe' },
{ column1: '2012-01-02', column2: 'Asia' },
];

In that case, only the count DataGroupType will be available, and you should implement your own groupY function if you are grouping your values by another strategy.

defaultValue

Default value to use when your dataset does not have a value for a date.

defaultValue: null | number | string,

Default: null

tip

The most common use case will be to set it to 0

This option used to be known as considerMissingDataAsZero in the previous versions

- + \ No newline at end of file diff --git a/docs/options/date.html b/docs/options/date.html index 964ff04..39ac6cc 100644 --- a/docs/options/date.html +++ b/docs/options/date.html @@ -13,7 +13,7 @@ - + @@ -28,7 +28,7 @@ all other locales are loaded on-demand. You can save a few milliseconds by including the dayjs locale script directly in your <head>, e.g. <script src="https://cdn.jsdelivr.net/npm/dayjs@1/locale/zh-cn.js"></script>, after the cal-heatmap.js <script>

Using a partial locale definition

Extend the default en locale, by passing a partial dayjs locale object.

Change the start of the week to monday
const cal = new CalHeatmap();
cal.paint({
date: { locale: { weekStart: 1 } },
});
tip

A locale object without the name property will be considered as partial

Using a full locale definition

Pass a full locale object. See dayjs locale documentation for object structure, and its github repo for some examples.

Pass a full custom locale
const cal = new CalHeatmap();
cal.paint({
date: {
locale: {
// Name property is required in order to not consider this object as partial
name: 'x-pseudo',
weekdays:
'S~úñdá~ý_Mó~ñdáý~_Túé~sdáý~_Wéd~ñésd~áý_T~húrs~dáý_~Fríd~áý_S~átúr~dáý'.split(
'_'
),
months:
'J~áñúá~rý_F~ébrú~árý_~Márc~h_Áp~ríl_~Máý_~Júñé~_Júl~ý_Áú~gúst~_Sép~témb~ér_Ó~ctób~ér_Ñ~óvém~bér_~Décé~mbér'.split(
'_'
),
weekStart: 1,
weekdaysShort: 'S~úñ_~Móñ_~Túé_~Wéd_~Thú_~Frí_~Sát'.split('_'),
monthsShort:
'J~áñ_~Féb_~Már_~Ápr_~Máý_~Júñ_~Júl_~Áúg_~Sép_~Óct_~Ñóv_~Déc'.split(
'_'
),
weekdaysMin: 'S~ú_Mó~_Tú_~Wé_T~h_Fr~_Sá'.split('_'),
ordinal: n => n,
formats: {
LT: 'HH:mm',
LTS: 'HH:mm:ss',
L: 'DD/MM/YYYY',
LL: 'D MMMM YYYY',
LLL: 'D MMMM YYYY HH:mm',
LLLL: 'dddd, D MMMM YYYY HH:mm',
},
relativeTime: {
future: 'í~ñ %s',
past: '%s á~gó',
s: 'á ~féw ~sécó~ñds',
m: 'á ~míñ~úté',
mm: '%d m~íñú~tés',
h: 'á~ñ hó~úr',
hh: '%d h~óúrs',
d: 'á ~dáý',
dd: '%d d~áýs',
M: 'á ~móñ~th',
MM: '%d m~óñt~hs',
y: 'á ~ýéár',
yy: '%d ý~éárs',
},
},
},
});

timezone

Date timezone.

timezone?: string;

Default: guessed from user browser.

Accepts any string representing a IANA timezone canonical name.

const cal = new CalHeatmap();
cal.paint({
date: { timezone: 'Europe/Paris' },
});
info

See the list of TZ database timezone here

- + \ No newline at end of file diff --git a/docs/options/domain.html b/docs/options/domain.html index d9283c6..92a134e 100644 --- a/docs/options/domain.html +++ b/docs/options/domain.html @@ -13,7 +13,7 @@ - + @@ -124,7 +124,7 @@ } }
Result
Loading...
Option scope

This only affect the domain's order, not the subDomain. See subDomain.sort to also set the subDomains sort order.

- + \ No newline at end of file diff --git a/docs/options/domain/label.html b/docs/options/domain/label.html index 850b6c2..8304d54 100644 --- a/docs/options/domain/label.html +++ b/docs/options/domain/label.html @@ -13,7 +13,7 @@ - + @@ -157,7 +157,7 @@ } }
Result
Loading...
- + \ No newline at end of file diff --git a/docs/options/itemSelector.html b/docs/options/itemSelector.html index 613aa87..9be993a 100644 --- a/docs/options/itemSelector.html +++ b/docs/options/itemSelector.html @@ -13,13 +13,13 @@ - +

itemSelector

Specify where the calendar should be rendered

itemSelector: Element | string;

This option accepts either an Element, or any W3C Selector string, such as #my-id or .myclass.

Default: #cal-heatmap


Usage

Example with the default itemSelector

index.html
/* Insert the following element somewhere in your page at the place where you
want to insert the calendar */
<div id="cal-heatmap"></div>
index.js
const cal = new CalHeatmap();
cal.paint(); // itemSelector can be omitted when using the default selector

Example with a custom itemselector

index.html
// Assuming you have the following element somewhere in your page
<div id="my-node"></div>
index.js
const cal = new CalHeatmap();
// These two following calls are identicals
cal.paint({ itemSelector: '#my-node' });
cal.paint({ itemSelector: document.getElementById('my-node') });
note

If the DOM node is not empty, the calendar will be inserted after the existing children.

- + \ No newline at end of file diff --git a/docs/options/range.html b/docs/options/range.html index f79451f..12caeb0 100644 --- a/docs/options/range.html +++ b/docs/options/range.html @@ -13,7 +13,7 @@ - + @@ -49,7 +49,7 @@ } }
Result
Loading...
- + \ No newline at end of file diff --git a/docs/options/scale.html b/docs/options/scale.html index 7b7fbde..f4e4f73 100644 --- a/docs/options/scale.html +++ b/docs/options/scale.html @@ -13,7 +13,7 @@ - + @@ -171,7 +171,7 @@ }
Result
Loading...
note

Cal-Heatmap is using Plot as the underlying library to handle the color scale. Take a look at their documentation for more advanced uses.

Some part of the scale documentation are extracted from their own documentation.

More advanced guide

You can read a more advanced guide about the various scale type in the Advanced section

- + \ No newline at end of file diff --git a/docs/options/subDomain.html b/docs/options/subDomain.html index 3485a15..3ea85f1 100644 --- a/docs/options/subDomain.html +++ b/docs/options/subDomain.html @@ -13,7 +13,7 @@ - + @@ -488,7 +488,7 @@ } }
Result
Loading...
Option scope

This only affect the subDomain's order, not the Domain. See Domain.sort to also set the domains sort order.

You can achieve a RTL result by setting both values to desc

- + \ No newline at end of file diff --git a/docs/options/theme.html b/docs/options/theme.html index 54f8e6e..23ddba2 100644 --- a/docs/options/theme.html +++ b/docs/options/theme.html @@ -13,7 +13,7 @@ - + @@ -22,7 +22,7 @@ as not all websites support dark/light mode.

info

All examples and demos in this documentation uses CSS to switch between light and dark mode, instead of the theme option, due to the way the documentation engine works.

Customize

All dark theme properties can be customized via CSS, use the [data-theme='dark'] prefix

- + \ No newline at end of file diff --git a/docs/options/verticalOrientation.html b/docs/options/verticalOrientation.html index 3cd2c1e..4374e0d 100644 --- a/docs/options/verticalOrientation.html +++ b/docs/options/verticalOrientation.html @@ -13,7 +13,7 @@ - + @@ -50,7 +50,7 @@ } }
Result
Loading...
- + \ No newline at end of file diff --git a/docs/plugins.html b/docs/plugins.html index 508ac9b..e412d02 100644 --- a/docs/plugins.html +++ b/docs/plugins.html @@ -13,14 +13,14 @@ - +

Plugins

Introduction

Cal-heatmap can be customized further with the help of plugins.

A plugin is setup within a paint() call.

interface PluginOptions {}
// IPluginContructor is the plugin's class
type PluginDefinition = [IPluginContructor, PluginOptions?];

const cal = new CalHeatmap();
cal.paint(options: Options, plugins?: PluginDefinition[] | PluginDefinition),

Core plugins

Below are the built-in plugins shipped with Cal-Heatmap

These plugins are not included in the main bundled, and have to be loaded separatly, alongside their dependencies. See each plugin documentation for details.

Usage

index.js
const cal = new CalHeatmap();
cal.paint({}, [[Legend], [Tooltip, { text: t => `${new Date(t)}` }]]);

Write your own plugins

Docs coming soon
- + \ No newline at end of file diff --git a/docs/plugins/calendarLabel.html b/docs/plugins/calendarLabel.html index 793b20e..ea2e5ac 100644 --- a/docs/plugins/calendarLabel.html +++ b/docs/plugins/calendarLabel.html @@ -13,7 +13,7 @@ - + @@ -107,7 +107,7 @@ } }
Result
Loading...

padding

Padding around the labels container, in pixel

padding: [number, number, number, number];

Expect an array of 4 numbers, in the same order as CSS padding property (top, right, bottom, left)

Default: [0, 0, 0, 0]

radius

Border radius of the label's background, in pixel

radius?: number,

Default: 0

width

Width of the label, in pixel

width?: number,

Default: subDomain's width

height

Height of the label, in pixel

height?: number,

Default: subDomains' height

caution

Total height can not be greater that the domain height

gutter

Space between each label, in pixel

gutter?: number,

Default: subDomains' gutter

textAlign

Horizontal alignment of the label

textAlign?: 'start' | 'middle' | 'end',

Default: middle

Styling

Text color

Default : inherit your parent text color

Overwrite the CSS with

.ch-plugin-calendar-label-text {
fill: red;
}

/* Or if you have multiple instance */
[data-key='my-custom-label'] .ch-plugin-calendar-label-text {
fill: red;
}

[data-key='my-other-label'] .ch-plugin-calendar-label-text {
fill: blue;
}

Background color

Default: transparent

Overwrite the CSS with

.ch-plugin-calendar-label-bg {
fill: blue;
}

/* Or if you have multiple instance */
[data-key='my-custom-label'] .ch-plugin-calendar-label-bg {
fill: blue;
}

[data-key='my-other-label'] .ch-plugin-calendar-label-bg {
fill: red;
}
- + \ No newline at end of file diff --git a/docs/plugins/legend.html b/docs/plugins/legend.html index c174852..bc22644 100644 --- a/docs/plugins/legend.html +++ b/docs/plugins/legend.html @@ -13,7 +13,7 @@ - + @@ -96,7 +96,7 @@ }
Result
Loading...

And more...

info

The legend uses ObservaleHQ Plot library under the hood. See this article for a more detailed and advanced customisation of the legend.

You can find more supported options directly on the library documentation

- + \ No newline at end of file diff --git a/docs/plugins/legendLite.html b/docs/plugins/legendLite.html index ef1b158..a64ccf1 100644 --- a/docs/plugins/legendLite.html +++ b/docs/plugins/legendLite.html @@ -13,7 +13,7 @@ - + @@ -210,7 +210,7 @@ } }
Result
Loading...
- + \ No newline at end of file diff --git a/docs/plugins/tooltip.html b/docs/plugins/tooltip.html index 03a1fda..c13506a 100644 --- a/docs/plugins/tooltip.html +++ b/docs/plugins/tooltip.html @@ -13,14 +13,14 @@ - +

Tooltip

This plugin adds a tooltip when hovering over a subDomain's cell

Install

Add the tooltip plugin and its dependendcy in your page's <head>, after cal-heatmap library <script>

<script src="https://unpkg.com/@popperjs/core@2"></script>
<script src="https://unpkg.com/cal-heatmap/dist/plugins/Tooltip.min.js"></script>

Usage

const cal = new CalHeatmap();
cal.paint({}, [[Tooltip, TOOLTIP_OPTIONS]]);

See TooltipOptions for the full list of available options.

TooltipOptions

// PopperOptions, see https://popper.js.org/docs/v2/constructors/#options
interface TooltipOptions extends PluginOptions, PopperOptions {
enabled: boolean;
text: (timestamp: number, value: number, dayjsDate: dayjs.Dayjs) => string;
}

enabled

Whether to enable the tooltip

Default: true

To customize the tooltip's UI, look for #ch-tooltip in the CSS.

text

A function returning the content of the tooltip

text: (timestamp: number, value: number, dayjsDate: dayjs.Dayjs) => string;

Default:

function (timestamp, value, dayjsDate) {
return `${value} - ${dayjsDate.toString()}`;
}

Arguments:

  • timestamp: The timestamp of the current subDomain, in ms, rounded to the start of the subDomain
  • value: The value of the current subDomain, from your data set
  • dayjsDate: A locale/timezone aware dayjs object, provided for easier date manipulation and formatting.

And more...

You can customize the underlying popper instance further, by passing the same object as createPopper's Options argument.

Styling

See #ch-tooltip properties in the CSS

- + \ No newline at end of file diff --git a/docs/showcase.html b/docs/showcase.html index ab6a5f7..a99ef41 100644 --- a/docs/showcase.html +++ b/docs/showcase.html @@ -13,7 +13,7 @@ - + @@ -732,7 +732,7 @@ } }
Result
Loading...
- + \ No newline at end of file diff --git a/docs/template.html b/docs/template.html index a91dee4..06f30ee 100644 --- a/docs/template.html +++ b/docs/template.html @@ -13,7 +13,7 @@ - + @@ -25,7 +25,7 @@ hour and minute templates.

Each of these templates are pretty basic, but will be enough for most use cases.

You can create and use a custom template if you wish to:

  • change the number of columns and rows (ex: all subDomains on same row)
  • change the time interval of a subDomain (ex: each subDomain equal 5min)
  • exclude some time window (ex: showing only weekdays)

How to use

Creating a template

A template is a javascript function taking 2 arguments and returning a TemplateResult.

type Template = function(DateHelper: DateHelper, options: Options) {
return TemplateResult;
}

Arguments

  • DateHelper: a Datehelper object, also used internally by the calendar for all date related computation. You should always rely on this helper whenever possible for date computation consistency.
  • Options: the Options object

Return value

type TemplateResult = {
name: string,
parent?: string,
rowsCount: (ts: number) => number,
columnsCount: (ts: number) => number,
mapping: (startTimestamp: number, endTimestamp: number) => SubDomain[],
extractUnit: (ts: number) => number,
};

name

Name of the subDomain type.

Will be used by subDomain.type options, and child template.

caution

Name should be unique

parent

Parent template's name

Optional, set the name of another template to inherit its options.

rowsCount

Total number of rows

This number may vary depending on the domain type.

Example from the hour template

rowsCount: ts => {
const TOTAL_ITEMS = 24;
const ROWS_COUNT = 6;
const { domain } = options;

switch (domain.type) {
case 'week':
return (TOTAL_ITEMS / ROWS_COUNT) * 7;
case 'month':
return (
(TOTAL_ITEMS / ROWS_COUNT) *
(domain.dynamicDimension ? DateHelper.date(ts).daysInMonth() : 31)
);
case 'day':
default:
return TOTAL_ITEMS / ROWS_COUNT;
}
};

columnsCount

Total number of columns

This number may vary depending on the domain type.

mapping

Function returning an array of SubDomain, used to populate each domain in the calendar.

A subDomain have 3 main properties:

type SubDomain = {
t: number,
x: number,
y: number,
};
  • t: the subDomain timestamp, rounded to the start of the time range

  • x: the row index of the cell

  • y: the column index of the cell

  • Rows are indexed from top to bottom, with the top one being 0.

  • Columns are indexed from left to right, with the left one being 0.

extractUnit

Function returning the start of the subDomain time range.

This function is used to bind your data to a subDomain

Example

  • If each subDomain is a 5min range, the timestamp for 9:18AM should return the timestamp for 9:15AM
  • If each subDomain is a weekday, the function should return the timestamp for the start of that day (00:00AM), and return null for a weekend.
tip

Take a look at the built-in templates on the github repository, for real-world examples.


Real world Example

Quarter subDomain template

Each subDomain represent 3 months.

const quarterTemplate = function (DateHelper) {
return {
name: 'quarter',
rowsCount() {
return 1;
},
columnsCount() {
return 4;
},
mapping: (startDate, endDate, defaultValues) =>
DateHelper.intervals('quarter', startDate, DateHelper.date(endDate)).map(
(d, index) => ({
t: d,
x: index,
y: 0,
...defaultValues,
})
),
extractUnit(d) {
return DateHelper.date(d).startOf('quarter').valueOf();
},
};
};

Days subDomain, with all days on the same row

Using day template as parent.

const sameRowDayTemplate = function (DateHelper) {
return {
name: 'day_same_row',
parent: 'day',
rowsCount() {
return 1;
},
columnsCount() {
return 31;
},
mapping: (startDate, endDate, defaultValues) =>
DateHelper.intervals('day', startDate, DateHelper.date(endDate)).map(
(d, index) => ({
t: d,
x: index,
y: 0,
...defaultValues,
})
),
// Missing extractUnit property, will be inherit from parent
};
};
const cal = new CalHeatmap();
cal.addTemplates(sameRowDayTemplate);
cal.paint({
range: 1,
domain: { type: 'month' },
subDomain: { type: 'day_same_row' },
});

Days subDomain, showing only the weekdays

See Showcase

- + \ No newline at end of file diff --git a/index.html b/index.html index 79cd7c3..f66444c 100644 --- a/index.html +++ b/index.html @@ -13,13 +13,13 @@ - +

Cal-Heatmap

Cal-Heatmap is a javascript charting library to create a time-series calendar heatmap

Date locale and timezone support

Customize the calendar language, timezone and locale specific setting, such as first day of the week

Animated Date Navigation

Browse the calendar dynamically, or jump to a specific date

Time granularity

Customize the layout and time interval: years, months, weeks, days, hours, minutes, and many more via plugins

Customizable

Customize the UI to your liking: cell size, padding, margin, color, cell position, RTL, etc...

Extensible

Add more functionality to the calendar via a plugin system

Typescript and tests

Written in typescript, ES6, and fully tested on real browsers via Browserstack

- + \ No newline at end of file diff --git a/search.html b/search.html index a9b9218..05c3973 100644 --- a/search.html +++ b/search.html @@ -13,13 +13,13 @@ - +

Search the documentation

- + \ No newline at end of file