@datawrapper/shared

v1.13.0-1

Published

shared functions used throughout datawrapper

Downloads

445

Readme

@datawrapper/shared

a set of shared methods that can be used throughout Datawrapper

Import single functions:

import purifyHtml from '@datawrapper/shared/purifyHtml';

Import entire package:

import shared from '@datawrapper/shared';
shared.purifyHtml();
shared.httpReq();

API reference

__(key, scope) ⇒ string

translates a message key. translations are originally stored in a Google spreadsheet that we're pulling into Datawrapper using the scripts/update-translations script, which stores them as :locale.json files in the /locale folders (both in core as well as inside plugin folders)

for the client-side translation to work we are also storing the translations in the global window.dw.backend.__messages object. plugins that need client-side translations must set "svelte": true in their plugin.json

Returns: string - -- the translated text

| Param | Type | Default | Description | | ----- | ------------------- | ----------------------------- | ----------------------------------------------------- | | key | string | | - the key to be translated, e.g. "signup / hed" | | scope | string | "core" | - the translation scope, e.g. "core" or a plugin name |


area(vertices) ⇒ number

Computes the area of a polygon

Returns: number - -- polygon area, might be negative

| Param | Type | Description | | -------- | -------------------------------- | ----------------------------------------------- | | vertices | Array.<array> | - polygon vertices as [[x,y], [x,y], ...] array |


arrayToObject(o) ⇒ object

This function fixes an uglyness when working with PHP backends. in PHP, there is no distiction between arrays and objects, so PHP converts an empty object {} to a empty array []. When this empty array then ends up in client-side JS functions which might start to assign values to the array using arr.foo = "bar" which results in a data structure like this:

| Param | Type | Description | | ----- | ------------------ | ----------- | | o | array | the input |

Example

console.log(arr);
[]
  foo: "bar"
  length: 0
  <prototype>: Array []

console.log(arrayToObject(arr));
Object { foo: "bar" }

autoTickFormat(column) ⇒ string

Convenient wrapper around autoTickFormatNumber and autoTickFormatDate. Returns either a numeral.js or day.js format, depending on the column type.

Returns: string - -- a numeral|dayjs format string

| Param | Type | Description | | ------ | ------------------- | -------------------------------------------------- | | column | object | - dw.column instance that is displayed on the axis |


autoTickFormatDate(range, precision) ⇒ string

auto-detects a nice default axis tick format for date columns based on the input range and precision

Returns: string - - day.js compatible format string

| Param | Type | Description | | --------- | ------------------- | ------------------------------ | ------- | ----- | ---- | --- | ---- | | range | array | [min, max] of the data | | precision | string | the input data precision (year | quarter | month | week | day | ...) |

Example

import { autoTickFormatDate } from '@datawrapper/shared/autoTickFormat';
autoTickFormatDate([new Date(2000, 0, 1), new Date(2002, 0, 1)], 'quarter'); // 'YYYY|[Q]Q'

autoTickFormatNumber(range) ⇒ string

auto-detects a nice default axis tick format for numeric columns based on the input range

Returns: string - - numeral.js compatible format string

| Param | Type | Description | | ----- | ------------------ | ---------------------- | | range | array | [min, max] of the data |

Example

import { autoTickFormatNumber } from '@datawrapper/shared/autoTickFormat';
autoTickFormatNumber([0, 100]); // '0,0.[00]'
autoTickFormatNumber([0.2, 0.7]); // '0,0.00[00]'

clone(object) ⇒ *

Clones an object

Returns: * - - the cloned thing

| Param | Type | Description | | ------ | --------------- | ------------------------------- | | object | * | the thing that should be cloned |


colorLightness(hexColor) ⇒ number

Returns the Lab lightness value of a given hexidecimal RGB color. Uses chroma-js to convert from Hex to Lab, but only adds a few hundreds bytes to your build.

To use this function, you have to manually install chroma-js using npm install chroma-js.

Returns: number - - the Lab lightness, between 0 (black) and 100 (white)

| Param | Type | Description | | -------- | ------------------- | --------------------------------------------------- | | hexColor | string | the RGB color as hexadecimal string, e.g. "#330066" |

Example

import colorLightness from '@datawrapper/shared/colorLightness';
colorLightness('#ff3399'); // 57.9

columnFormatter(numeral, column, metadata, axis) ⇒ function

This function returns a formatting function based, given a column object, a metadata object and the axis column name.

| Param | Type | Description | | -------- | ------------------- | --------------------------- | | numeral | object | Numeral.js instance | | column | object | the date column object | | metadata | object | the full metadata object | | axis | string | the column name of the axis |


columnNameToVariable(name) ⇒ string

converts a column name to a variable name that can be used in the custom column editor. variable names can't contain spaces and special characters and are also converted to lowercase.

Returns: string - -- variable name

| Param | Type | Description | | ----- | ------------------- | -------------------- | | name | string | - name of the column |

Example

import columnNameToVariable from '@datawrapper/shared/columnNameToVariable';

columnNameToVariable('GDP (per cap.)'); // gdp_per_cap

combinations(input) ⇒ Array.<array>

computes all combinations of input elements

Returns: Array.<array> - -- array of combinations

| Param | Type | Description | | ----- | -------------------------------- | -------------------------------------------------------- | | input | Array.<array> | - array of input objects, could be numbers, strings, etc |

Example

// returns [['a','b'], ['a'], ['b']]
combinations(['a', 'b']);

Example

// returns [[1,2,3], [1,2], [1,3], [1], [2,3], [2], [3]]
combinations([1, 2, 3]);

dateColumnFormatter(column) ⇒ function

This function returns a date formatting function based on a dw column object. The implementation is backwards-compatible with our old Globalize-based date formatting, but uses dayjs under the hood.

| Param | Type | Description | | ------ | ------------------- | ---------------------- | | column | object | the date column object |


decodeHtml(input) ⇒ string

Removes all html tags and decodes html entities like  

| Param | Type | | ----- | ------------------- | | input | string |


defaultColors(theme) ⇒ *

defines colors for the various chart elements like axis text, gridlines, bar background etc. based on the theme background color, and some other optional theme parameters

Returns: * - -- object with color definitions and blendColor function

| Param | Type | Description | | ----- | --------------- | ------------------------ | | theme | * | - theme data for a chart |

Example

// returns {"tickText":{"secondary":"#9d9d9d","primary":"#d9d9d9"},"series":"#f1f1f1","value":"#d9d9d9","axis":"#f1f1f1","gridline":"#707070","fallbackBaseColor":"#f1f1f1", blendColor: function}
defaultColors({ colors: { background: '#333333' } });

Example

// returns {"tickText":{"secondary":"#ffffff","primary":"#ffffff"},"series":"#ffffff","value":"#fef2e4","axis":"#ffffff","gridline":"#fedeb5","fallbackBaseColor":"#ffffff"}
defaultColors({
    colors: {
        bgBlendRatios: { gridline: 0.5, tickText: { primary: 0, secondary: 0 } },
        chartContentBaseColor: '#ffffff',
        background: '#FCB716'
    }
});

defaultOverlayTitle(vis, colName) ⇒ string

returns the overlays column title

| Param | Type | | ------- | ------------------- | | vis | object | | colName | string |


~~deleteJSON(url, callback) ⇒ Promise~~

Deprecated

Download and parse a remote JSON endpoint via DELETE. credentials are included automatically Use httpReq or delete instead.

| Param | Type | | -------- | --------------------- | | url | string | | callback | function |

Example

import { deleteJSON } from '@datawrapper/shared/fetch';

deleteJSON('http://api.example.org/chart/123').then(() => {
    console.log('deleted!');
});

drawPattern(parameters)

draws a configurable pattern into an svg pattern def, so that it can be used as a fill

| Param | Type | Description | | ---------- | --------------- | ---------------------------------- | | parameters | * | - style parameters for the pattern |


equalish(a, b) ⇒ boolean

returns true if two numeric values are close enough

| Param | Type | | ----- | ------------------- | | a | number | | b | number |

Example

// returns true
equalish(0.333333, 1 / 3);

Example

// returns false
equalish(0.333, 1 / 3);

escapeHtml(unsafe) ⇒ string

returns escaped HTML that can be used to display untrusted content

| Param | Type | | ------ | ------------------- | | unsafe | string |


estimateTextWidth(text, fontSize) ⇒ number

returns the estimated width of a given text in Roboto. this method has proven to be a good compromise between pixel-perfect but expensive text measuring methods using canvas or getClientBoundingRect and just multiplying the number of characters with a fixed width.

be warned that this is just a rough estimate of the text width. the character widths will vary from typeface to typeface and may be off quite a bit for some fonts (like monospace fonts).

| Param | Type | Description | | -------- | ------------------- | ---------------------------------------------- | | text | string | the text to measure | | fontSize | number | the output font size (optional, default is 14) |

Example

import estimateTextWidth from '@datawrapper/shared/estimateTextWidth';
// or import {estimateTextWidth} from '@datawrapper/shared';
const width = estimateTextWidth('my text', 12);

~~fetchJSON(url, method, credentials, body, callback) ⇒ Promise~~

Deprecated

Download and parse a remote JSON document. Use httpReq instead

| Param | Type | Description | | ----------- | --------------------------------------------- | ---------------------------------------------------------------- | | url | string | | | method | string | HTTP method, either GET, POST or PUT | | credentials | string | undefined | set to "include" if cookies should be passed along CORS requests | | body | string | | | callback | function | |

Example

import { fetchJSON } from '@datawrapper/shared/fetch';
fetchJSON('http://api.example.org', 'GET', 'include');

formatNumber(numeral, value, options) ⇒ string

special number formatting that can deal with microtypography and "prepend currencies" (e.g., −$1234.57)

Returns: string - - the formatted number

| Param | Type | Description | | ----------------- | ------------------- | -------------------------------------- | | numeral | object | Numeral.js instance | | value | number | the number to format | | options | object | options, see below | | options.format | string | numeral.js compatible number format | | options.prepend | string | string to prepend to number | | options.append | string | string to append to number | | options.minusChar | string | custom character to use for minus | | options.multiply | number | multiply number before applying format |

Example

// returns '1234.57'
formatNumber(numeral, 1234.567);

Example

// returns '−$1234.57'
formatNumber(numeral, -1234.567, { prepend: '$' });

get(object, key, _default) ⇒

Safely access object properties without throwing nasty cannot access X of undefined errors if a property along the way doesn't exist.

Returns: the value

| Param | Type | Description | | --------- | -------------------------------------------------------- | ------------------------------------------------------------------ | | object | | the object which properties you want to acccess | | key | String | Array.<String> | path to the property as a dot-separated string or array of strings | | _default | * | the fallback value to be returned if key doesn't exist |

Example

import get from '@datawrapper/shared/get';
const someObject = { key: { list: ['a', 'b', 'c'] } };
get(someObject, 'key.list[2]'); // returns 'c'
get(someObject, 'missing.key'); // returns undefined
get(someObject, 'missing.key', false); // returns false

~~getJSON(url, credentials, callback) ⇒ Promise~~

Deprecated

Download and parse a JSON document via GET. Use httpReq or get instead.

| Param | Type | Description | | ----------- | --------------------------------------------- | ------------------------------------------------- | | url | string | | | credentials | string | undefined | optional, set to undefined to disable credentials | | callback | function | |

Example

import { getJSON } from '@datawrapper/shared/fetch';
// use it callback style
getJSON('http://api.example.org', 'include', function (data) {
    console.log(data);
});
// or promise-style
getJSON('http://api.example.org').then(data => {
    console.log(data);
});

highlightTimer(action, delay) ⇒ object

A delayed highlight setter

| Param | Type | Description | | ------ | --------------------- | ------------------------------------------------------------------------------------------ | | action | function | the highlight action callback | | delay | int | how long something needs to be highlighted before the highlight triggers (in milliseconds) |

Example

import { highlightTimer } from '@datawrapper/shared';
const myTimer = highlightTimer(value => {
    if (value) {
        selection.style('opacity', d => (d === value ? 1 : 0.3));
    } else {
        selection.style('opacity', 1);
    }
});

lines.on('mouseenter', d => myTimer.set(d));
chart.on('mouseleave', myTimer.clear);

httpReq(path, options) ⇒ Promise

The response body is automatically parsed according to the response content type.

Returns: Promise - promise of parsed response body or raw response

| Param | Type | Description | | --------------- | -------------------- | ------------------------------------------------------------------ | | path | string | the url path that gets appended to baseUrl | | options.body | object | raw body to be send with req | | options.payload | object | raw JSON payload to be send with req (will overwrite options.body) | | options.raw | boolean | disable parsing of response body, returns raw response | | options.baseUrl | string | base for url, defaults to dw api domain | | options | * | see documentation for window.fetch for additional options |

Example

import httpReq from '@datawrapper/shared/httpReq';
let res = await httpReq('/v3/charts', {
    method: 'post',
    payload: {
        title: 'My new chart'
    }
});
import { post } from '@datawrapper/shared/httpReq';
res = await post('/v3/charts', {
    payload: {
        title: 'My new chart'
    }
});
// send raw csv
await httpReq.put(`/v3/charts/${chartId}/data`, {
    body: csvData,
    headers: {
        'Content-Type': 'text/csv'
    }
});

httpReq.delete()

Like httpReq but with fixed http method DELETE

See: httpReq


httpReq.get()

Like httpReq but with fixed http method GET

See: httpReq


httpReq.head()

Like httpReq but with fixed http method HEAD

See: httpReq


httpReq.patch()

Like httpReq but with fixed http method PATCH

See: httpReq


httpReq.post()

Like httpReq but with fixed http method POST

See: httpReq


httpReq.put()

Like httpReq but with fixed http method PUT

See: httpReq


isValidUrl(input) ⇒ boolean

checks if a given string is a valid URL

| Param | Type | | ----- | ------------------- | | input | string |


kMeans(values, numCluster) ⇒ array.<Array.<number>>

Performs one-dimensional k-means clustering on an array of numbers. Useful for finding n groups of "similar values".

Returns: array.<Array.<number>> - - array of clusters

| Param | Type | Description | | ---------- | --------------------------------- | ------------------------- | | values | Array.<number> | sorted array of numbers | | numCluster | number | the desired cluster count |

Example

import kMeans from '@datawrapper/shared/kMeans';

const values = [1, 1.1, 1.2, 2.1, 3, 3.1, 3.2, 3.3, 7, 7.1, 10];
// returns [[1, 1.1, 1.2, 2.1], [3, 3.1, 3.2, 3.3], [7, 7.1, 10]]
kMeans(values, 3);

loadScript(src, callback)

injects a <script> element to the page to load a new JS script

| Param | Type | | -------- | --------------------- | | src | string | | callback | function |

Example

import { loadScript } from '@datawrapper/shared/fetch';

loadScript('/static/js/library.js', () => {
    console.log('library is loaded');
});

loadStylesheet(src, callback)

injects a <link> element to the page to load a new stylesheet

| Param | Type | | -------- | ------------------------------------------------- | | src | string | opts | | callback | function |

Example

import { loadStylesheet } from '@datawrapper/shared/fetch';

loadStylesheet('/static/css/library.css', () => {
    console.log('library styles are loaded');
});

normalizeAlphaNumKey(key) ⇒ string

normalize an alphanumerical key for less-strict matching (e.g. in maps)

Returns: string - - normalized key

| Param | Type | Description | | ----- | ------------------- | ------------------ | | key | string | alphanumerical key |


normalizeNumKey(key) ⇒ number

normalize a numerical key for less-strict matching (e.g. in maps)

Returns: number - - normalized key

| Param | Type | Description | | ----- | ------------------------------------------ | ------------- | | key | string | number | numerical key |


numberColumnFormatter(numeral, config) ⇒ function

This function returns a number formatting function based on a column configuration object stored in metadata.data.column-format. The implementation is backwards-compatible with our old Globalize-based number formatting, but uses numeral under the hood.

| Param | Type | Description | | ------- | ------------------- | -------------------------------------- | | numeral | object | Numeral.js instance | | config | object | the column configuration from metadata |


observeFonts(fontsJSON, typographyJSON) ⇒ Promise

Function that returns a promise, that resolves when all fonts, specified in fontsJSON and typographyJSON have been loaded.

| Param | Type | | -------------- | ----------------------------------------- | | fontsJSON | Object | Array | | typographyJSON | Object |


opts : object

Properties

| Name | Type | Description | | ------------- | ----------------------- | ---------------------------------- | | src | string | stylesheet URL to load | | parentElement | DOMElement | DOM element to append style tag to |


~~patchJSON(url, body, callback) ⇒ Promise~~

Deprecated

| Param | Type | | -------- | --------------------- | | url | string | | body | string | | callback | function |

Example

import { patchJSON } from '@datawrapper/shared/fetch';

patchJSON(
    'http://api.example.org',
    JSON.stringify({
        query: 'foo',
        page: 12
    })
);

postEvent(chartId) ⇒ function

Use this function to post event messages out of Datawrapper iframe embeds to the parent website.

| Param | Type | Description | | ------- | ------------------- | ----------------------------------------------- | | chartId | string | the chart id each message should be signed with |

Example

import genPostEvent from '@datawrapper/shared/postEvent';
const postEvent = genPostEvent(chart.get('id'));
postEvent('bar:hover', { value: 123 });

~~postJSON(url, body, callback) ⇒ Promise~~

Deprecated

Download and parse a remote JSON endpoint via POST. credentials are included automatically. Use httpReq or post instead.

| Param | Type | | -------- | --------------------- | | url | string | | body | string | | callback | function |

Example

import { postJSON } from '@datawrapper/shared/fetch';

postJSON(
    'http://api.example.org',
    JSON.stringify({
        query: 'foo',
        page: 12
    })
);

purifyHtml(input, allowed) ⇒ string

Remove all non-whitelisted html tags from the given string

Returns: string - - the cleaned html output

| Param | Type | Description | | ------- | ------------------- | ------------------------------------------------------------------------------------------- | | input | string | dirty html input | | allowed | string | list of allowed tags, defaults to <a><b><br><br/><i><strong><sup><sub><strike><u><em><tt> |


~~putJSON(url, body, callback) ⇒ Promise~~

Deprecated

Download and parse a remote JSON endpoint via PUT. credentials are included automatically Use httpReq or put instead.

| Param | Type | | -------- | --------------------- | | url | string | | body | string | | callback | function |

Example

import { putJSON } from '@datawrapper/shared/fetch';

putJSON(
    'http://api.example.org',
    JSON.stringify({
        query: 'foo',
        page: 12
    })
);

round(value, decimals) ⇒ number

rounds a value to a certain number of decimals

Returns: number - - rounded value

| Param | Type | Description | | -------- | ------------------- | ----------------------- | | value | number | the value to be rounded | | decimals | number | the number of decimals |

Example

import round from '@datawrapper/shared/round';
round(1.2345); // 1
round(1.2345, 2); // 1.23
round(12345, -2); // 12300

set(object, key, value) ⇒

safely set object properties without throwing nasty cannot access X of undefined errors if a property along the way doesn't exist.

Returns: the value

| Param | Type | Description | | ------ | -------------------------------------------------------- | ------------------------------------------------------------------ | | object | | the object which properties you want to acccess | | key | String | Array.<String> | path to the property as a dot-separated string or array of strings | | value | * | the value to be set |


significantDimension(values, tolerance) ⇒ number

computes the significant dimension for a list of numbers That's the number of decimals to which we can round the numbers without loosing information

Returns: number - - number of significant dimensions (= the number of decimals)

| Param | Type | Description | | --------- | --------------------------------- | -------------------------------------------------- | | values | Array.<number> | list of input numbers | | tolerance | number | percent of input values that we allow to "collide" |

Example

import { significantDimension } from '@datawrapper/shared/significantDimension';
significantDimension([0, 10, 20, 30]); // -1

smartRound(values, addPrecision, tolerance) ⇒

rounds an array of numbers to the least number of decimals without loosing any information due to the rounding

Returns: the rounded values

| Param | Type | Description | | ------------ | ------------------- | ---------------------------------------------------------------------------- | | values | array | the numbers to be rounded | | addPrecision | number | force more precision (=numbers of decimals) to the rounding | | tolerance | number | the percent of uniq input values that we can tolerate to lose after rounding |

Example

import { smartRound } from '@datawrapper/shared/smartRound';
smartRound([9, 10.5714, 12.1428, 13.7142]); // [9, 11, 12, 14]
smartRound([9, 10.5714, 12.1428, 12.4142]); // [9, 10.6, 12.1, 12.4]

tailLength(value) ⇒ number

returns the length of the "tail" of a number, meaning the number of meaningful decimal places

| Param | Type | | ----- | ------------------- | | value | number |

Example

// returns 3
tailLength(3.123);

Example

// returns 2
tailLength(3.12999999);

toFixed(value) ⇒ string

Automatically converts a numeric value to a string. this is better than the default number to string conversion in JS which sometimes produces ugly strings like "3.999999998"

| Param | Type | | ----- | ------------------- | | value | number |

Example

import toFixed from '@datawrapper/shared/toFixed';
// returns '3.1'
toFixed(3.100001);

trackEvent(category, category, category, category)

tracks a custom event in Matomo

| Param | Type | Description | | -------- | ------------------------------------------ | ------------------------- | | category | string | the event category | | category | string | the event action | | category | string | the event name | | category | string | number | the event value, optional |


trackPageView(loadTime)

tracks a custom page view in Matomo. Useful for single page apps in Datawrapper, such as the locator maps UI. The page title and URL are automatically detected using the window object.

| Param | Type | Description | | -------- | ------------------- | ---------------------------------------------------- | | loadTime | number | optional page load time, has to be measured manually |


truncate(str, start, end) ⇒ string

Shorten a string by removing characters from the middle

| Param | Type | Description | | ----- | ------------------- | ------------------------------------- | | str | string | | | start | number | characters to keep at start of string | | end | number | characters to keep at end off string |

Example

import truncate from '@datawrapper/shared/truncate';
// returns 'This is a…tring'
truncate('This is a very very long string');