Comments (21)
Thanks for the information! Plotly intends to focus on feature development, bug fixing and performance. Internally we are satisfied with a minimal build system and vanilla JS as this reaches a wide developer and user base. TypeScript is an amazing project that brings static tooling and safety to JS so we have marked this issue as community
and are open to any TypeScript definition PRs.
from plotly.js.
Just opened a PR for the definitions file I've been working on: DefinitelyTyped/DefinitelyTyped#15379
from plotly.js.
Just figured I'd update this with a TSD for 1.53.0 if anyone has use for it.
plotly.js.zip
from plotly.js.
Plotly folks,
I have been working with my own TypeScript definition file for plotly.js for some time now. I would be glad to contribute it to the project. I do not have the bandwidth to get involved with plotly development so I would have to simply hand off the index.d.ts file to you. It accurately describes a UMD library. It "belongs" with you as a versioned artifact. It would be great for you to release it with the distribution. The TypeScript project describes how to integrate the file with your project and NPM. I can't attach the file because the type is not supported. Please shoot me an email at [email protected] and I'll send it to you.
Best,
David Geo Holmes https://github.com/geometryzen
BTW. Love Plotly. I'm pushing it into education. See it at https://www.stemcstudio.com (best in Chrome).
from plotly.js.
I built a simple react typescript plotlyjs module for the people who looking for simple solution in typescript, check it here
https://github.com/davidctj/react-plotlyjs-ts
from plotly.js.
I have a Gradle-based TSD generator that parses the plot-schema.json file and generates a TypeScript TSD. I'll attach it here in case anyone finds it useful. If I hear back that it's working for others, I may add it to DefinitelyTyped.
from plotly.js.
@etpinard take a look at https://github.com/DefinitelyTyped/DefinitelyTyped/
from plotly.js.
@etpinard the Handbook from the Microsoft website is a good starting point.
http://www.typescriptlang.org/Handbook
You may also be interested by their tutorials and samples:
http://www.typescriptlang.org/Tutorial
http://www.typescriptlang.org/Samples
This blog is also an interesting resource: http://www.johnpapa.net/typescriptpost1/
As xuyang2 said the DefinitelyTyped repo is the place the search for existing TS declaration files.
Here is the folder corresponding to Highcharts: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/highcharts
About IDE support:
- Visual Studio has a built-in support of TypeScript
- Intellij and Webstorm also provide a support through a free plugin. I think it now installed by default.
- Under Eclipse (I develop my TS project under Eclipse) I suggest to use the free plugin from the palantir company: https://github.com/palantir/eclipse-typescript
Now about the methodology you have two possibilities:
- Keep the development of plotly.js in pure JS and provide TS declaration files. They will contain interfaces describing your functions, classes and objects. This will be done in a "d.ts" file (d standing for declaration).
- Develop plotly.js directly in TS. You will benefit from the type-safety of the language which simplifies the refactoring of big projects. The compiler will generate for you a JS file that could be used as a dro-pin replacement of plotly.js and a plotly.d.ts file corresponding to the API of your plotly.ts file. This plotly.d.ts will be useful for other TS developers.
I will suggest to start with approach 1. and to switch to 2. if you think it is useful for your team.
Note that the declarations defined in approach 1 could leveraged when switching to the TS dev, so you won't loose your work.
As a short example if you have a JS config object defining points coordinates, you w'ill define something like that in JS:
var point = { x: 10, y: 20 };
function plotPoint(p) {
// your JS code here
}
plotPoint(point);
To provide a TS type describing this JS object here is what you should have in your "d.ts" file:
interface Point {
x: number;
y: number;
}
declare function plotPoint(p: Point): void
Now if you define your code directly in a TS file, this should be like this:
interface Point {
x: number;
y: number;
}
function plotPoint(p: Point): void = {
// your TS code here
}
var point = <Point>{ x: 10, y: 20 };
plotPoint(point);
Compiling your TS file will result in the JS and .d.ts code above. But as you can see when switch from d.ts to .ts coding, we re-use interfaces defined in the d.ts file. Only the TS code has to be ported from the JS one.
Hope this will be useful.
Best.
from plotly.js.
Adding the legend layout: DefinitelyTyped/DefinitelyTyped#17108
from plotly.js.
@alanpurple, would you mind adding those types to our definition in DefinitelyTyped? Our communities definition isn't complete unfortunately, as there are tons and tons of graphs and components in plotly.
If you don't want to, then everything should work just fine if you use any
type since it's just javascript and the plotly library will work without typescript.
I'd be happy to review the PR for you and help where needed.
To make additions:
- clone definitlytyped repo
- make branch for your change
- find the plotly.js definition file in the repo and make your changes.
- You can test your changes against your code by copying the definition file into your project somewhere and including it with your tsconfig.json (I think the
types
compiler option is where that goes, orfiles
- To figure out how to write the definition file, I read the plotly code looking for
attribute
files. I also usedany
types while testing my comprehension of the source code.
- Add an example (helps others a lot!)
- Once it looks good, publish the branch and make a PR. You can @mention me (and I think it auto mentions the original contributor)
from plotly.js.
I've never used typescript before.
Could you point me to good resources or examples of other projects that support typescript (I couldn't find the relevant file in the highcharts repo).
from plotly.js.
@etpinard Videos on Typescript
- Evolving JavaScript with TypeScript by Anders Hejlsberg
- Introducing TypeScript by Anders Hejlsberg
- Typescript Demystified
from plotly.js.
@stemcstudio , plotly has starter definitions on DefinitelyTyped. Why not consider creating a pull request for your definitions?
That way, people usings Typings and TypeSearch (npm @types) can simply use it.
Also check out this: DefinitelyTyped/DefinitelyTyped#7202
from plotly.js.
As I said in issue board of plotly.js repository, this is not compatible with 3dscatterplot ( try example in official page )
from plotly.js.
there is no datatype for boxplot
from plotly.js.
@chrisgervang Okay I'll try
from plotly.js.
@brian428 This looks great 😍
I'm no expert, but I've bumped into limitations of the current index.d.ts on DefinitelyTypes, e.g. I want a table
, which is included in your index.d.ts. If there is anything I (or my team) can do to help get this on DefinitelyTyped, that would be awesome 🙏
Edit: I naively (and erroneously) tried copying your index.d.ts into node_modules. Oops 😅 Noob question, but how can I use your declaration instead of (or in addition to) the one currently on DefinitelyTyped?
Edit^2: I modified the index.d.ts from the zip file. It is VERY complete. 25K lines 😱 We are testing it. If we get it to work, should we submit a PR to DefinitelyTyped? It will be very breaking though.
Edit^3: We made some more progress, but it is not smooth sailing. Bar
, Scatter
and Table
are working now. In some case, e.g. x:
for Bar
only accepted number[]
so we changed it to number[] | string[]
, etc. A number of changes like that. I think it might be worth considering adapting this. I'm happy to share our revisions.
from plotly.js.
@EricForgy sorry, I hadn't checked this thread in a while. I'm sure there are places where things aren't quite right (which will almost always be due to related issues with the Plotly schema JSON that the TSD is generated from, or less common "multiple-type" options for various properties). Since I mainly use the scattergl plots, and not the other plot types, I'm sure it'll take a range of people trying to use it to really squash any lingering problems with the TSD.
from plotly.js.
-
Are the long lists of choices, e.g. names of marker symbols (
Drawing.symbolList
), provided separately or are they missing? I'm thankful for the current (community provided) type definitions, but the "magic strings" are what I most wanted to get from there since I have trouble remembering them & thus frequently make mistakes. -
Rather than using union types of literal strings (e.g.
'linear' | 'spline' | 'hv' | 'vh' | 'hvh' | 'vhv'
), could we use anenum
instead? This helps make those lists accessible so that consuming applications do not need to duplicate them. e.g. One could do something like this:// definition export const enum LineShapeType { Linear = 'linear', Spline = 'spline', HV = 'hv', VH = 'vh', HVH = 'hvh', VHV = 'vhv', } // ... 'line.shape': LineShapeType; // ... // user code import { LineShapeType } from 'plotly.js'; // ... const choices = Object.values(LineShapeType); // ...
-
Would a PR related to these be welcome? (@chrisgervang, @martinduparc, and other contributors)
FWIW, here's how I'm extracting this currently (somewhat crude, but does the job):
const input = '0|"circle"|100|"circle-open"|200|"circle-dot"|300|"circle-open-dot"|1|"square"|101|"square-open"|201|"square-dot"|301|"square-open-dot"|2|"diamond"|102|"diamond-open"|202|"diamond-dot"|302|"diamond-open-dot"|3|"cross"|103|"cross-open"|203|"cross-dot"|303|"cross-open-dot"|4|"x"|104|"x-open"|204|"x-dot"|304|"x-open-dot"|5|"triangle-up"|105|"triangle-up-open"|205|"triangle-up-dot"|305|"triangle-up-open-dot"|6|"triangle-down"|106|"triangle-down-open"|206|"triangle-down-dot"|306|"triangle-down-open-dot"|7|"triangle-left"|107|"triangle-left-open"|207|"triangle-left-dot"|307|"triangle-left-open-dot"|8|"triangle-right"|108|"triangle-right-open"|208|"triangle-right-dot"|308|"triangle-right-open-dot"|9|"triangle-ne"|109|"triangle-ne-open"|209|"triangle-ne-dot"|309|"triangle-ne-open-dot"|10|"triangle-se"|110|"triangle-se-open"|210|"triangle-se-dot"|310|"triangle-se-open-dot"|11|"triangle-sw"|111|"triangle-sw-open"|211|"triangle-sw-dot"|311|"triangle-sw-open-dot"|12|"triangle-nw"|112|"triangle-nw-open"|212|"triangle-nw-dot"|312|"triangle-nw-open-dot"|13|"pentagon"|113|"pentagon-open"|213|"pentagon-dot"|313|"pentagon-open-dot"|14|"hexagon"|114|"hexagon-open"|214|"hexagon-dot"|314|"hexagon-open-dot"|15|"hexagon2"|115|"hexagon2-open"|215|"hexagon2-dot"|315|"hexagon2-open-dot"|16|"octagon"|116|"octagon-open"|216|"octagon-dot"|316|"octagon-open-dot"|17|"star"|117|"star-open"|217|"star-dot"|317|"star-open-dot"|18|"hexagram"|118|"hexagram-open"|218|"hexagram-dot"|318|"hexagram-open-dot"|19|"star-triangle-up"|119|"star-triangle-up-open"|219|"star-triangle-up-dot"|319|"star-triangle-up-open-dot"|20|"star-triangle-down"|120|"star-triangle-down-open"|220|"star-triangle-down-dot"|320|"star-triangle-down-open-dot"|21|"star-square"|121|"star-square-open"|221|"star-square-dot"|321|"star-square-open-dot"|22|"star-diamond"|122|"star-diamond-open"|222|"star-diamond-dot"|322|"star-diamond-open-dot"|23|"diamond-tall"|123|"diamond-tall-open"|223|"diamond-tall-dot"|323|"diamond-tall-open-dot"|24|"diamond-wide"|124|"diamond-wide-open"|224|"diamond-wide-dot"|324|"diamond-wide-open-dot"|25|"hourglass"|125|"hourglass-open"|26|"bowtie"|126|"bowtie-open"|27|"circle-cross"|127|"circle-cross-open"|28|"circle-x"|128|"circle-x-open"|29|"square-cross"|129|"square-cross-open"|30|"square-x"|130|"square-x-open"|31|"diamond-cross"|131|"diamond-cross-open"|32|"diamond-x"|132|"diamond-x-open"|33|"cross-thin"|133|"cross-thin-open"|34|"x-thin"|134|"x-thin-open"|35|"asterisk"|135|"asterisk-open"|36|"hash"|136|"hash-open"|236|"hash-dot"|336|"hash-open-dot"|37|"y-up"|137|"y-up-open"|38|"y-down"|138|"y-down-open"|39|"y-left"|139|"y-left-open"|40|"y-right"|140|"y-right-open"|41|"line-ew"|141|"line-ew-open"|42|"line-ns"|142|"line-ns-open"|43|"line-ne"|143|"line-ne-open"|44|"line-nw"|144|"line-nw-open"'
const array = input.split('|');
const list = array.reduce((list, item, i, a) => {
// Process even indices (extract pairs)
if (i % 2 === 0) {
const code = parseInt(item, 10);
const name = a[i+1].slice(1, -1); // remove quotation marks
list.push({ code, name });
}
return list;
}, []);
const codes = list.map(x => x.code);
const names = list.map(x => x.name);
console.log(JSON.stringify(list, null, ' '));
Output
[
{
"code": 0,
"name": "circle"
},
{
"code": 100,
"name": "circle-open"
},
{
"code": 200,
"name": "circle-dot"
},
{
"code": 300,
"name": "circle-open-dot"
},
{
"code": 1,
"name": "square"
},
{
"code": 101,
"name": "square-open"
},
{
"code": 201,
"name": "square-dot"
},
{
"code": 301,
"name": "square-open-dot"
},
{
"code": 2,
"name": "diamond"
},
{
"code": 102,
"name": "diamond-open"
},
{
"code": 202,
"name": "diamond-dot"
},
{
"code": 302,
"name": "diamond-open-dot"
},
{
"code": 3,
"name": "cross"
},
{
"code": 103,
"name": "cross-open"
},
{
"code": 203,
"name": "cross-dot"
},
{
"code": 303,
"name": "cross-open-dot"
},
{
"code": 4,
"name": "x"
},
{
"code": 104,
"name": "x-open"
},
{
"code": 204,
"name": "x-dot"
},
{
"code": 304,
"name": "x-open-dot"
},
{
"code": 5,
"name": "triangle-up"
},
{
"code": 105,
"name": "triangle-up-open"
},
{
"code": 205,
"name": "triangle-up-dot"
},
{
"code": 305,
"name": "triangle-up-open-dot"
},
{
"code": 6,
"name": "triangle-down"
},
{
"code": 106,
"name": "triangle-down-open"
},
{
"code": 206,
"name": "triangle-down-dot"
},
{
"code": 306,
"name": "triangle-down-open-dot"
},
{
"code": 7,
"name": "triangle-left"
},
{
"code": 107,
"name": "triangle-left-open"
},
{
"code": 207,
"name": "triangle-left-dot"
},
{
"code": 307,
"name": "triangle-left-open-dot"
},
{
"code": 8,
"name": "triangle-right"
},
{
"code": 108,
"name": "triangle-right-open"
},
{
"code": 208,
"name": "triangle-right-dot"
},
{
"code": 308,
"name": "triangle-right-open-dot"
},
{
"code": 9,
"name": "triangle-ne"
},
{
"code": 109,
"name": "triangle-ne-open"
},
{
"code": 209,
"name": "triangle-ne-dot"
},
{
"code": 309,
"name": "triangle-ne-open-dot"
},
{
"code": 10,
"name": "triangle-se"
},
{
"code": 110,
"name": "triangle-se-open"
},
{
"code": 210,
"name": "triangle-se-dot"
},
{
"code": 310,
"name": "triangle-se-open-dot"
},
{
"code": 11,
"name": "triangle-sw"
},
{
"code": 111,
"name": "triangle-sw-open"
},
{
"code": 211,
"name": "triangle-sw-dot"
},
{
"code": 311,
"name": "triangle-sw-open-dot"
},
{
"code": 12,
"name": "triangle-nw"
},
{
"code": 112,
"name": "triangle-nw-open"
},
{
"code": 212,
"name": "triangle-nw-dot"
},
{
"code": 312,
"name": "triangle-nw-open-dot"
},
{
"code": 13,
"name": "pentagon"
},
{
"code": 113,
"name": "pentagon-open"
},
{
"code": 213,
"name": "pentagon-dot"
},
{
"code": 313,
"name": "pentagon-open-dot"
},
{
"code": 14,
"name": "hexagon"
},
{
"code": 114,
"name": "hexagon-open"
},
{
"code": 214,
"name": "hexagon-dot"
},
{
"code": 314,
"name": "hexagon-open-dot"
},
{
"code": 15,
"name": "hexagon2"
},
{
"code": 115,
"name": "hexagon2-open"
},
{
"code": 215,
"name": "hexagon2-dot"
},
{
"code": 315,
"name": "hexagon2-open-dot"
},
{
"code": 16,
"name": "octagon"
},
{
"code": 116,
"name": "octagon-open"
},
{
"code": 216,
"name": "octagon-dot"
},
{
"code": 316,
"name": "octagon-open-dot"
},
{
"code": 17,
"name": "star"
},
{
"code": 117,
"name": "star-open"
},
{
"code": 217,
"name": "star-dot"
},
{
"code": 317,
"name": "star-open-dot"
},
{
"code": 18,
"name": "hexagram"
},
{
"code": 118,
"name": "hexagram-open"
},
{
"code": 218,
"name": "hexagram-dot"
},
{
"code": 318,
"name": "hexagram-open-dot"
},
{
"code": 19,
"name": "star-triangle-up"
},
{
"code": 119,
"name": "star-triangle-up-open"
},
{
"code": 219,
"name": "star-triangle-up-dot"
},
{
"code": 319,
"name": "star-triangle-up-open-dot"
},
{
"code": 20,
"name": "star-triangle-down"
},
{
"code": 120,
"name": "star-triangle-down-open"
},
{
"code": 220,
"name": "star-triangle-down-dot"
},
{
"code": 320,
"name": "star-triangle-down-open-dot"
},
{
"code": 21,
"name": "star-square"
},
{
"code": 121,
"name": "star-square-open"
},
{
"code": 221,
"name": "star-square-dot"
},
{
"code": 321,
"name": "star-square-open-dot"
},
{
"code": 22,
"name": "star-diamond"
},
{
"code": 122,
"name": "star-diamond-open"
},
{
"code": 222,
"name": "star-diamond-dot"
},
{
"code": 322,
"name": "star-diamond-open-dot"
},
{
"code": 23,
"name": "diamond-tall"
},
{
"code": 123,
"name": "diamond-tall-open"
},
{
"code": 223,
"name": "diamond-tall-dot"
},
{
"code": 323,
"name": "diamond-tall-open-dot"
},
{
"code": 24,
"name": "diamond-wide"
},
{
"code": 124,
"name": "diamond-wide-open"
},
{
"code": 224,
"name": "diamond-wide-dot"
},
{
"code": 324,
"name": "diamond-wide-open-dot"
},
{
"code": 25,
"name": "hourglass"
},
{
"code": 125,
"name": "hourglass-open"
},
{
"code": 26,
"name": "bowtie"
},
{
"code": 126,
"name": "bowtie-open"
},
{
"code": 27,
"name": "circle-cross"
},
{
"code": 127,
"name": "circle-cross-open"
},
{
"code": 28,
"name": "circle-x"
},
{
"code": 128,
"name": "circle-x-open"
},
{
"code": 29,
"name": "square-cross"
},
{
"code": 129,
"name": "square-cross-open"
},
{
"code": 30,
"name": "square-x"
},
{
"code": 130,
"name": "square-x-open"
},
{
"code": 31,
"name": "diamond-cross"
},
{
"code": 131,
"name": "diamond-cross-open"
},
{
"code": 32,
"name": "diamond-x"
},
{
"code": 132,
"name": "diamond-x-open"
},
{
"code": 33,
"name": "cross-thin"
},
{
"code": 133,
"name": "cross-thin-open"
},
{
"code": 34,
"name": "x-thin"
},
{
"code": 134,
"name": "x-thin-open"
},
{
"code": 35,
"name": "asterisk"
},
{
"code": 135,
"name": "asterisk-open"
},
{
"code": 36,
"name": "hash"
},
{
"code": 136,
"name": "hash-open"
},
{
"code": 236,
"name": "hash-dot"
},
{
"code": 336,
"name": "hash-open-dot"
},
{
"code": 37,
"name": "y-up"
},
{
"code": 137,
"name": "y-up-open"
},
{
"code": 38,
"name": "y-down"
},
{
"code": 138,
"name": "y-down-open"
},
{
"code": 39,
"name": "y-left"
},
{
"code": 139,
"name": "y-left-open"
},
{
"code": 40,
"name": "y-right"
},
{
"code": 140,
"name": "y-right-open"
},
{
"code": 41,
"name": "line-ew"
},
{
"code": 141,
"name": "line-ew-open"
},
{
"code": 42,
"name": "line-ns"
},
{
"code": 142,
"name": "line-ns-open"
},
{
"code": 43,
"name": "line-ne"
},
{
"code": 143,
"name": "line-ne-open"
},
{
"code": 44,
"name": "line-nw"
},
{
"code": 144,
"name": "line-nw-open"
}
]
from plotly.js.
@jacobq I'm not sure if you're referring to the current TSD on DefinitelyTyped, or my new TSD (zip is above). But for my version, the main challenge is that it is generated from the Plotly source code (mainly via plot-schema.json
). The TSD has to be generated (IMO), because the changes come too quickly and the API is too vast to try and keep up with it manually. My version, which I think is fairly complete, is over 26,000 lines (including doc comments).
I'm not sure that creating enums for the various "magic strings" will work, because an ambient TSD is a compile-time-only artifact. (If there's a way to export concrete types from a TSD, I'm not aware of it.) But it might be possible to generate a non-TSD "companion" file that could be copied into a project.
from plotly.js.
I'm not sure if you're referring to the current TSD on DefinitelyTyped, or my new TSD (zip is above).
I had been using what I found on DefinitelyTyped (yarn add -D @types/plotly.js
).
The TSD has to be generated (IMO), because the changes come too quickly and the API is too vast to try and keep up with it manually.
I agree. Ideally, plotly.js would define and export these itself to ensure that they're always consistent and to avoid the need for a separate package. In the mean time, generating it programmatically for each plotly.js release seems like a reasonable stop-gap solution.
I'm not sure that creating enums for the various "magic strings" will work, because an ambient TSD is a compile-time-only artifact. (If there's a way to export concrete types from a TSD, I'm not aware of it.) But it might be possible to generate a non-TSD "companion" file that could be copied into a project.
While I don't know all the technical details, I've seen this done in other definition files in DefinitelyType's repo. For example in @types/webcl
(try searching the repo for "const enum"
; there are a lot of results). Maybe it's not as simple as I imagine, but since string enums are just named string literals they should be functionally the same (i.e. everything happens at compile time).
from plotly.js.
Related Issues (20)
- Mismatch between legend and line colors when using uppercase css colors HOT 1
- Item toggle behavior when using multiple legends HOT 8
- insiderange on multiple overlaid axes edge case
- [Feature Request] Adding a Button to Copy Image to Clipboard HOT 1
- BUG: standoff causes axis title position to break if no tick labels
- Shapes - fill to infinity/-infinity
- Adding a dendrogram to heatmaps
- Smith Chart (scattersmith) pan & zoom functionality HOT 2
- axes range not working. Range is +-1, data is 0->1.6e10 HOT 3
- ScatterGL throws ` TypeError: r[v] is undefined` when using frames HOT 1
- Clicks are sometimes missed with clickmode layout key HOT 4
- Tooltip pointer (triangle) not correctly positioned with hovermode 'x'
- Plotly chart conflict with touchstart / touchmove event to scroll smartphone screen HOT 1
- [BUG] Rangeslider won't reset after zooming out HOT 1
- Inconsistent behavior when providing an array of marker sizes in "markers" mode on scatter3D
- hoverdistance broken in 3D scatter plots; hover radius vs click radius?
- `scattergl` line plots no longer working after upgrading to 2.29.1 HOT 3
- Combining rangemode tozero and tickformat set to "," produces unexpected results
- REOPENING BUG - pie chart hover label hidden
- Hoverlabel overlaps each other
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from plotly.js.