You've already forked wakapi-readme-stats
Bar graph added.
This commit is contained in:
27
node_modules/vega-scenegraph/LICENSE
generated
vendored
Normal file
27
node_modules/vega-scenegraph/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2015-2018, University of Washington Interactive Data Lab
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
55
node_modules/vega-scenegraph/README.md
generated
vendored
Normal file
55
node_modules/vega-scenegraph/README.md
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
# vega-scenegraph
|
||||
|
||||
[Vega](https://github.com/vega/vega) scenegraph and renderers.
|
||||
|
||||
Renderers and event handlers for Vega's mark-based scenegraph. This package supports both pixel-based (canvas) and vector graphics (SVG) output. Renderers can either (re-)draw a complete scene or perform incremental re-rendering for a set of provided "dirty" items. A fast SVG string renderer is also provided to generate static SVG for export.
|
||||
|
||||
The [node-canvas](https://github.com/Automattic/node-canvas) library is used for server-side canvas rendering and bounds calculation. Node-canvas requires the native Cairo graphics library and may attempt to compile native code as part of the installation process. In some instances this may result in installation hiccups. Should you run into issues, you are likely to resolve them more quickly if you first search for help regarding node-canvas (as opposed to vega-scenegraph) installation. However, node-canvas is not a strict dependency, and is not needed for SVG rendering. Bounds calculation can be performed without node-canvas, though in the case of text marks the resulting bounds may be inaccurate due to approximate text size calculations.
|
||||
|
||||
## Scenegraph Definition
|
||||
|
||||
The Vega scenegraph is a hierarchical (tree) data structure. The levels of the tree alternate between an enclosing *mark* definition and contained sets of mark instances called *items*.
|
||||
|
||||
For example, here is a simple scenegraph containing three rectangles:
|
||||
|
||||
```json
|
||||
{
|
||||
"marktype": "rect",
|
||||
"items": [
|
||||
{"x": 0, "y": 0, "width": 50, "height": 50, "fill": "steelblue"},
|
||||
{"x": 100, "y": 50, "width": 50, "height": 50, "fill": "firebrick"},
|
||||
{"x": 50, "y": 100, "width": 50, "height": 50, "fill": "forestgreen"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The supported mark types are rectangles (`rect`), plotting symbols (`symbol`), general paths or polygons (`path`), circular arcs (`arc`), filled areas (`area`), lines (`line`), images (`image`), text labels (`text`), and chart gridlines or rules (`rule`). Each item has a set of supported properties (`x`, `y`, `width`, `fill`, and so on) appropriate to the mark type.
|
||||
|
||||
Scenegraphs may also contain `group` marks, which serve as containers for other marks. For example, a top-level group mark may look like:
|
||||
|
||||
```json
|
||||
{
|
||||
"marktype": "group",
|
||||
"items": [
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 200,
|
||||
"height": 200,
|
||||
"items": [...] // array of contained mark instances
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the group *mark* contains only a single group *item*. In practice, a group mark may contain any number of group items, for example to describe a scene with multiple layers or sub-plots.
|
||||
|
||||
For more information regarding supported mark properties, please see the [Vega marks documentation](https://vega.github.io/vega/docs/marks/).
|
||||
|
||||
## Scenegraph Serialization
|
||||
|
||||
The top-level export of this package includes `fromJSON` and `toJSON` methods to support scenegraph serialization. The `fromJSON` method expects a JSON string as input (similar to the examples listed above). It will then add additional parent pointers to the tree structure. For example, each item will have a `mark` property pointing to its parent mark, and each mark will have a `group` property pointing to its parent group (if any). The `toJSON` method maps a scenegraph instance to a JSON string, stripping any parent pointers or other non-standard properties.
|
||||
|
||||
## Test Suite
|
||||
|
||||
The vega-scengraph test suite compares rendered output for both Canvas (PNG) and SVG (text) renderers. Due to differences among platforms, pixel-level rendering by node-canvas can differ across operating systems. As a result, some test cases may break when running on a system other than Mac OS X (our standard platform for testing). If you are running on Linux or Windows and experience test failures, it does not necessarily indicate an issue with vega-scenegraph. In such cases, we recommend running the node-canvas test-server (`npm run test-server` from the node-canvas repository) to compare server-side and client-side rendering.
|
||||
2150
node_modules/vega-scenegraph/build/vega-scenegraph-schema.json
generated
vendored
Normal file
2150
node_modules/vega-scenegraph/build/vega-scenegraph-schema.json
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
5340
node_modules/vega-scenegraph/build/vega-scenegraph.js
generated
vendored
Normal file
5340
node_modules/vega-scenegraph/build/vega-scenegraph.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
node_modules/vega-scenegraph/build/vega-scenegraph.min.js
generated
vendored
Normal file
1
node_modules/vega-scenegraph/build/vega-scenegraph.min.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
68
node_modules/vega-scenegraph/index.js
generated
vendored
Normal file
68
node_modules/vega-scenegraph/index.js
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
import {resetSVGGradientId} from './src/Gradient';
|
||||
import {resetSVGClipId} from './src/util/svg/clip';
|
||||
|
||||
export {default as Bounds} from './src/Bounds';
|
||||
export {default as Gradient} from './src/Gradient';
|
||||
export {default as GroupItem} from './src/GroupItem';
|
||||
export {default as ResourceLoader} from './src/ResourceLoader';
|
||||
export {default as Item} from './src/Item';
|
||||
export {default as Scenegraph} from './src/Scenegraph';
|
||||
|
||||
export {default as Handler} from './src/Handler';
|
||||
export {default as Renderer} from './src/Renderer';
|
||||
export {default as CanvasHandler} from './src/CanvasHandler';
|
||||
export {default as CanvasRenderer} from './src/CanvasRenderer';
|
||||
export {default as SVGHandler} from './src/SVGHandler';
|
||||
export {default as SVGRenderer} from './src/SVGRenderer';
|
||||
export {default as SVGStringRenderer} from './src/SVGStringRenderer';
|
||||
export {RenderType, renderModule} from './src/modules';
|
||||
export {intersect} from './src/intersect';
|
||||
|
||||
export {default as Marks} from './src/marks/index';
|
||||
|
||||
export {default as boundClip} from './src/bound/boundClip';
|
||||
export {default as boundContext} from './src/bound/boundContext';
|
||||
export {default as boundStroke} from './src/bound/boundStroke';
|
||||
export {default as boundItem} from './src/bound/boundItem';
|
||||
export {default as boundMark} from './src/bound/boundMark';
|
||||
|
||||
export {default as pathCurves} from './src/path/curves';
|
||||
export {default as pathSymbols} from './src/path/symbols';
|
||||
export {default as pathRectangle} from './src/path/rectangle';
|
||||
export {default as pathTrail} from './src/path/trail';
|
||||
export {default as pathParse} from './src/path/parse';
|
||||
export {default as pathRender} from './src/path/render';
|
||||
|
||||
export {default as point} from './src/util/point';
|
||||
export {domCreate, domFind, domChild, domClear} from './src/util/dom';
|
||||
export {openTag, closeTag} from './src/util/tags';
|
||||
export {
|
||||
font,
|
||||
fontFamily,
|
||||
fontSize,
|
||||
lineHeight,
|
||||
multiLineOffset,
|
||||
textMetrics
|
||||
} from './src/util/text';
|
||||
|
||||
export {sceneEqual, pathEqual} from './src/util/equal';
|
||||
export {sceneToJSON, sceneFromJSON} from './src/util/serialize';
|
||||
export {
|
||||
intersectPath,
|
||||
intersectPoint,
|
||||
intersectRule,
|
||||
intersectBoxLine
|
||||
} from './src/util/intersect';
|
||||
export {
|
||||
zorder as sceneZOrder,
|
||||
visit as sceneVisit,
|
||||
pickVisit as scenePickVisit
|
||||
} from './src/util/visit';
|
||||
|
||||
// deprecated, remove in next major version
|
||||
export {resetSVGClipId} from './src/util/svg/clip';
|
||||
|
||||
export function resetSVGDefIds() {
|
||||
resetSVGClipId();
|
||||
resetSVGGradientId();
|
||||
}
|
||||
68
node_modules/vega-scenegraph/package.json
generated
vendored
Normal file
68
node_modules/vega-scenegraph/package.json
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"_from": "vega-scenegraph@~4.8.3",
|
||||
"_id": "vega-scenegraph@4.8.3",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-2GznqXm/py7/XX9juohFbLYQTKxHY5VNRZLHc0bL35Nd7lShKeOlHY9uVkHw2FoLLCz78UcXFminWM8lddvGxw==",
|
||||
"_location": "/vega-scenegraph",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "range",
|
||||
"registry": true,
|
||||
"raw": "vega-scenegraph@~4.8.3",
|
||||
"name": "vega-scenegraph",
|
||||
"escapedName": "vega-scenegraph",
|
||||
"rawSpec": "~4.8.3",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "~4.8.3"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/vega",
|
||||
"/vega-functions",
|
||||
"/vega-view",
|
||||
"/vega-view-transforms"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/vega-scenegraph/-/vega-scenegraph-4.8.3.tgz",
|
||||
"_shasum": "11b557019175ec5ddc258c3a5eb7371e64cec5e1",
|
||||
"_spec": "vega-scenegraph@~4.8.3",
|
||||
"_where": "/home/prabhatdev/Documents/opensource/gitHubStats/waka-readme-stats/node_modules/vega",
|
||||
"author": {
|
||||
"name": "Jeffrey Heer",
|
||||
"url": "http://idl.cs.washington.edu"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/vega/vega/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"dependencies": {
|
||||
"d3-path": "^1.0.9",
|
||||
"d3-shape": "^1.3.7",
|
||||
"vega-canvas": "^1.2.2",
|
||||
"vega-loader": "^4.3.0",
|
||||
"vega-scale": "^7.0.0",
|
||||
"vega-util": "^1.14.0"
|
||||
},
|
||||
"deprecated": false,
|
||||
"description": "Vega scenegraph and renderers.",
|
||||
"gitHead": "8fe8d36961c128df8300e6bc4fe6aac1e537bbe0",
|
||||
"homepage": "https://github.com/vega/vega#readme",
|
||||
"license": "BSD-3-Clause",
|
||||
"main": "build/vega-scenegraph.js",
|
||||
"module": "index",
|
||||
"name": "vega-scenegraph",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vega/vega.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "yarn rollup && yarn schema",
|
||||
"postbuild": "terser build/vega-scenegraph.js -c -m -o build/vega-scenegraph.min.js",
|
||||
"postpublish": "git push && git push --tags",
|
||||
"prebuild": "rimraf build && mkdir build",
|
||||
"prepublishOnly": "yarn test && yarn build",
|
||||
"pretest": "yarn prebuild && yarn rollup && yarn schema",
|
||||
"rollup": "rollup -f umd -g d3-path:d3,d3-shape:d3,vega-canvas:vega,vega-loader:vega,vega-scale:vega,vega-util:vega -n vega -o build/vega-scenegraph.js -- index.js",
|
||||
"schema": "node schema > build/vega-scenegraph-schema.json",
|
||||
"test": "tape -r ./test/__init__ 'test/**/*-test.js'"
|
||||
},
|
||||
"version": "4.8.3"
|
||||
}
|
||||
421
node_modules/vega-scenegraph/schema.js
generated
vendored
Normal file
421
node_modules/vega-scenegraph/schema.js
generated
vendored
Normal file
@@ -0,0 +1,421 @@
|
||||
function duplicate(_) {
|
||||
return JSON.parse(JSON.stringify(_));
|
||||
}
|
||||
|
||||
function extend(_) {
|
||||
for (var x, k, i=1, len=arguments.length; i<len; ++i) {
|
||||
x = arguments[i];
|
||||
for (k in x) { _[k] = x[k]; }
|
||||
}
|
||||
return _;
|
||||
}
|
||||
|
||||
function build(strict) {
|
||||
const schema = duplicate(BASE);
|
||||
for (const type in MARKS) {
|
||||
buildMark(type, schema.refs, strict);
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
|
||||
function buildMark(type, refs, strict) {
|
||||
const mark = duplicate(MARK_BASE);
|
||||
mark.properties.marktype.enum = [ type ];
|
||||
mark.properties.items.items.$ref += type;
|
||||
if (strict) mark.additionalProperties = false;
|
||||
|
||||
const item = duplicate(ITEM_BASE);
|
||||
extend(item.properties, MARKS[type].properties || {});
|
||||
if (strict) item.additionalProperties = false;
|
||||
|
||||
refs.mark.oneOf.push({$ref: '#/refs/mark-' + type});
|
||||
refs['mark-'+type] = mark;
|
||||
refs['item-'+type] = item;
|
||||
}
|
||||
|
||||
function svg_path() {
|
||||
// Based on http://www.w3.org/TR/SVG/paths.html#PathDataBNF
|
||||
const wsp = '[ \t\r\f]*',
|
||||
csp = '([ \t\r\f]+,?[ \t\r\f]*|,[ \t\r\f]*)?',
|
||||
sep = csp + '?',
|
||||
pos = '[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?',
|
||||
num = '[-+]?' + pos,
|
||||
nseq = num + '(' + sep + num + ')*',
|
||||
p = num + sep + num,
|
||||
p2 = p + sep + p,
|
||||
p3 = p + '(' + sep + p + '){2}',
|
||||
pseq = p + '(' + sep + p + ')*',
|
||||
arc = pos + sep + pos + sep + num + csp + '[01]' + sep + '[01]' + sep + p,
|
||||
m = '[Mm]' + wsp + pseq,
|
||||
lt = '[LlTt]' + wsp + pseq,
|
||||
hv = '[HhVv]' + wsp + nseq,
|
||||
c = '[Cc]' + wsp + p3 + '(' + sep + p3 + ')*',
|
||||
qs = '[QqSs]' + wsp + p2 + '(' + sep + p2 + ')*',
|
||||
a = '[Aa]' + wsp + arc + '(' + sep + arc + ')*',
|
||||
z = '[Zz]',
|
||||
draw = '(' + [z, lt, hv, c, qs, a].join('|') + ')',
|
||||
move = m + wsp + '(' + draw + '(' + sep + draw + ')*' + ')?',
|
||||
path = wsp + '(' + move + '(' + sep + move + ')*' + ')?' + wsp;
|
||||
return path;
|
||||
}
|
||||
|
||||
const COLOR_NAMES = 'aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood|cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|darkblue|darkcyan|darkgoldenrod|darkgray|darkgreen|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|darksalmon|darkseagreen|darkslateblue|darkslategray|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dodgerblue|firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|gray|green|greenyellow|honeydew|hotpink|indianred|indigo|ivory|khaki|lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgreen|lightpink|lightsalmon|lightseagreen|lightskyblue|lightslategray|lightsteelblue|lightyellow|lime|limegreen|linen|magenta|maroon|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|navy|oldlace|olive|olivedrab|orange|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|papayawhip|peachpuff|peru|pink|plum|powderblue|purple|rebeccapurple|red|rosybrown|royalblue|saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|snow|springgreen|steelblue|tan|teal|thistle|tomato|turquoise|violet|wheat|white|whitesmoke|yellow|yellowgreen';
|
||||
|
||||
function css_color_names() {
|
||||
return COLOR_NAMES.split('|').map(
|
||||
name => name.split('')
|
||||
.map(c => `[${c.toUpperCase()}${c.toLowerCase()}]`)
|
||||
.join('')
|
||||
).join('|');
|
||||
}
|
||||
|
||||
const BASE = {
|
||||
'$schema': 'http://json-schema.org/draft-06/schema#',
|
||||
'title': 'Vega scenegraph',
|
||||
'description': 'Vega scenegraph model.',
|
||||
'oneOf': [ { '$ref': '#/refs/mark' } ],
|
||||
'refs': {
|
||||
'mark': { 'oneOf': [] },
|
||||
'path': {
|
||||
'type': 'string',
|
||||
'pattern': '^' + svg_path() + '$'
|
||||
},
|
||||
'paint': {
|
||||
'oneOf': [
|
||||
{ '$ref': '#/refs/color' },
|
||||
{ '$ref': '#/refs/linearGradient' },
|
||||
{ '$ref': '#/refs/radialGradient' }
|
||||
]
|
||||
},
|
||||
'color': {
|
||||
'oneOf': [
|
||||
{
|
||||
'type': 'string',
|
||||
'pattern': '^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'pattern': '^rgb\\([ \t\f]*([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(,[ \t\f]*([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){2}[ \t\f]*\\)$'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'pattern': '^rgb\\([ \t\f]*([0-9]|[1-9][0-9]|100)%(,[ \t\f]*([0-9]|[1-9][0-9]|100)%){2}[ \t\f]*\\)$'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'pattern': '^hsl\\([ \t\f]*([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-9][0-9]|3[0-5][0-9]|360)(,[ \t\f]*([0-9]|[1-9][0-9]|100)%){2}[ \t\f]*\\)$'
|
||||
},
|
||||
{
|
||||
'type': 'string',
|
||||
'pattern': '^(' + css_color_names() + ')$'
|
||||
}
|
||||
]
|
||||
},
|
||||
'gradientStop': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'offset': { 'type': 'number' },
|
||||
'color': { '$ref': '#/refs/color' }
|
||||
},
|
||||
'required': ['offset', 'color']
|
||||
},
|
||||
'linearGradient': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'gradient': { 'enum': [ 'linear' ] },
|
||||
'id': { 'type': 'string' },
|
||||
'x1': { 'type': 'number' },
|
||||
'y1': { 'type': 'number' },
|
||||
'x2': { 'type': 'number' },
|
||||
'y2': { 'type': 'number' },
|
||||
'stops': {
|
||||
'type': 'array',
|
||||
'items': { '$ref': '#/refs/gradientStop' }
|
||||
}
|
||||
},
|
||||
'required': ['gradient', 'stops'],
|
||||
'additionalProperties': false
|
||||
},
|
||||
'radialGradient': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'gradient': { 'enum': [ 'radial' ] },
|
||||
'id': { 'type': 'string' },
|
||||
'x1': { 'type': 'number' },
|
||||
'y1': { 'type': 'number' },
|
||||
'r1': { 'type': 'number' },
|
||||
'x2': { 'type': 'number' },
|
||||
'y2': { 'type': 'number' },
|
||||
'r2': { 'type': 'number' },
|
||||
'stops': {
|
||||
'type': 'array',
|
||||
'items': { '$ref': '#/refs/gradientStop' }
|
||||
}
|
||||
},
|
||||
'required': ['gradient', 'stops'],
|
||||
'additionalProperties': false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const MARK_BASE = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'marktype': { 'enum': null },
|
||||
'name': { 'type': 'string' },
|
||||
'role': { 'type': 'string' },
|
||||
'description': { 'type': 'string' },
|
||||
'aria': { 'type': 'boolean' },
|
||||
'interactive': { 'type': 'boolean', 'default': true },
|
||||
'items': {
|
||||
'type': 'array',
|
||||
'items': { '$ref': '#/refs/item-' }
|
||||
},
|
||||
'zindex': { 'type': 'number' }
|
||||
},
|
||||
'required': [ 'marktype' ]
|
||||
};
|
||||
|
||||
const BLEND_MODE = [
|
||||
null,
|
||||
'multiply',
|
||||
'screen',
|
||||
'overlay',
|
||||
'darken',
|
||||
'lighten',
|
||||
'color-dodge',
|
||||
'color-burn',
|
||||
'hard-light',
|
||||
'soft-light',
|
||||
'difference',
|
||||
'exclusion',
|
||||
'hue',
|
||||
'saturation',
|
||||
'color',
|
||||
'luminosity'
|
||||
];
|
||||
|
||||
const ITEM_BASE = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'x': { 'type': 'number' },
|
||||
'y': { 'type': 'number' },
|
||||
'width': { 'type': 'number' },
|
||||
'height': { 'type': 'number' },
|
||||
'blend': { 'enum': BLEND_MODE, 'default': null },
|
||||
'opacity': { 'type': 'number', 'default': 1 },
|
||||
'fill': { '$ref': '#/refs/paint' },
|
||||
'fillOpacity': { 'type': 'number', 'default': 1 },
|
||||
'stroke': { '$ref': '#/refs/paint' },
|
||||
'strokeOpacity': { 'type': 'number', 'default': 1 },
|
||||
'strokeWidth': { 'type': 'number', 'default': 1 },
|
||||
'strokeCap': { 'enum': [ 'butt', 'cap', 'round' ], 'default': 'butt' },
|
||||
'strokeJoin': { 'enum': [ 'miter', 'round', 'bevel' ], 'default': 'miter' },
|
||||
'strokeMiterLimit': { 'type': 'number' },
|
||||
'strokeDash': { 'type': 'array', 'items': { 'type': 'number' } },
|
||||
'strokeDashOffset': { 'type': 'number', 'default': 0 },
|
||||
'zindex': { 'type': 'number' },
|
||||
'cursor': { 'type': 'string' },
|
||||
'href': { 'type': 'string', 'format': 'uri-reference' },
|
||||
'tooltip': {},
|
||||
'description': { 'type': 'string' },
|
||||
'aria': { 'type': 'boolean' },
|
||||
'ariaRole': { 'type': 'string' },
|
||||
'ariaRoleDescription': { 'type': 'string' }
|
||||
}
|
||||
};
|
||||
|
||||
const AREA_INTERPOLATE = [
|
||||
'basis',
|
||||
'cardinal',
|
||||
'catmull-rom',
|
||||
'linear',
|
||||
'monotone',
|
||||
'natural',
|
||||
'step',
|
||||
'step-after',
|
||||
'step-before'
|
||||
];
|
||||
|
||||
const LINE_INTERPOLATE = [
|
||||
'basis',
|
||||
'basis-closed',
|
||||
'basis-open',
|
||||
'bundle',
|
||||
'cardinal',
|
||||
'cardinal-closed',
|
||||
'cardinal-open',
|
||||
'catmull-rom',
|
||||
'catmull-rom-closed',
|
||||
'catmull-rom-open',
|
||||
'linear',
|
||||
'linear-closed',
|
||||
'monotone',
|
||||
'natural',
|
||||
'step',
|
||||
'step-after',
|
||||
'step-before'
|
||||
];
|
||||
|
||||
const TEXT_BASELINE = [
|
||||
'alphabetic',
|
||||
'top',
|
||||
'middle',
|
||||
'bottom',
|
||||
'line-top',
|
||||
'line-bottom'
|
||||
];
|
||||
|
||||
const TEXT_FONT_WEIGHT = [
|
||||
'normal',
|
||||
'bold',
|
||||
'bolder',
|
||||
'lighter',
|
||||
100,
|
||||
200,
|
||||
300,
|
||||
400,
|
||||
500,
|
||||
600,
|
||||
700,
|
||||
800,
|
||||
900
|
||||
];
|
||||
|
||||
const MARKS = {
|
||||
'group': {
|
||||
'properties': {
|
||||
'clip': { 'type': 'boolean' },
|
||||
'cornerRadius': { 'type': 'number' },
|
||||
'cornerRadiusTopLeft': { 'type': 'number' },
|
||||
'cornerRadiusTopRight': { 'type': 'number' },
|
||||
'cornerRadiusBottomRight': { 'type': 'number' },
|
||||
'cornerRadiusBottomLeft': { 'type': 'number' },
|
||||
'items': { 'type': 'array', 'items': { '$ref': '#/refs/mark' } },
|
||||
'strokeForeground': { 'type': 'boolean' },
|
||||
'strokeOffset': { 'type': 'number' }
|
||||
}
|
||||
},
|
||||
'arc': {
|
||||
'properties': {
|
||||
'startAngle': { 'type': 'number' },
|
||||
'endAngle': { 'type': 'number' },
|
||||
'padAngle': { 'type': 'number' },
|
||||
'innerRadius': { 'type': 'number' },
|
||||
'outerRadius': { 'type': 'number' },
|
||||
'cornerRadius': { 'type': 'number' }
|
||||
}
|
||||
},
|
||||
'area': {
|
||||
'properties': {
|
||||
'defined': { 'type': 'boolean' },
|
||||
'interpolate': { 'enum': AREA_INTERPOLATE },
|
||||
'tension': { 'type': 'number' },
|
||||
'orient': { 'enum': [ 'horizontal', 'vertical' ] }
|
||||
}
|
||||
},
|
||||
'image': {
|
||||
'properties': {
|
||||
'url': { 'type': 'string', 'format': 'uri-reference' },
|
||||
'aspect': { 'type': 'boolean', 'default': true },
|
||||
'smooth': { 'type': 'boolean', 'default': true },
|
||||
'align': {
|
||||
'enum': [ 'left', 'center', 'right' ],
|
||||
'default': 'left'
|
||||
},
|
||||
'baseline': {
|
||||
'enum': [ 'top', 'middle', 'bottom' ],
|
||||
'default': 'top'
|
||||
}
|
||||
}
|
||||
},
|
||||
'line': {
|
||||
'properties': {
|
||||
'defined': { 'type': 'boolean' },
|
||||
'interpolate': { 'enum': LINE_INTERPOLATE },
|
||||
'tension': { 'type': 'number' },
|
||||
'orient': { 'enum': [ 'horizontal', 'vertical' ] },
|
||||
'size': { 'type': 'number' }
|
||||
}
|
||||
},
|
||||
'path': {
|
||||
'properties': {
|
||||
'angle': { 'type': 'number' },
|
||||
'path': { '$ref': '#/refs/path' },
|
||||
'scaleX': { 'type': 'number' },
|
||||
'scaleY': { 'type': 'number' }
|
||||
}
|
||||
},
|
||||
'rect': {
|
||||
'properties': {
|
||||
'cornerRadius': { 'type': 'number' },
|
||||
'cornerRadiusTopLeft': { 'type': 'number' },
|
||||
'cornerRadiusTopRight': { 'type': 'number' },
|
||||
'cornerRadiusBottomRight': { 'type': 'number' },
|
||||
'cornerRadiusBottomLeft': { 'type': 'number' }
|
||||
}
|
||||
},
|
||||
'rule': {
|
||||
'properties': {
|
||||
'x2': { 'type': 'number' },
|
||||
'y2': { 'type': 'number' }
|
||||
}
|
||||
},
|
||||
'symbol': {
|
||||
'properties': {
|
||||
'angle': { 'type': 'number', 'default': 0 },
|
||||
'size': { 'type': 'number', 'default': 100 },
|
||||
'shape': { 'type': 'string' }
|
||||
}
|
||||
},
|
||||
'text': {
|
||||
'properties': {
|
||||
'text': {
|
||||
'oneOf': [
|
||||
{ 'type': 'string' },
|
||||
{ 'type': 'array', 'items': { 'type': 'string' } }
|
||||
]
|
||||
},
|
||||
'limit': { 'type': 'number', 'default': 0 },
|
||||
'lineHeight': { 'type': 'number' },
|
||||
'dir': { 'type': 'string', 'default': 'ltr' },
|
||||
'ellipsis': { 'type': 'string', 'default': '\u2026' },
|
||||
'align': {
|
||||
'enum': [ 'left', 'center', 'right' ],
|
||||
'default': 'left'
|
||||
},
|
||||
'baseline': {
|
||||
'enum': TEXT_BASELINE,
|
||||
'default': 'alphabetic'
|
||||
},
|
||||
'angle': { 'type': 'number', 'default': 0 },
|
||||
'theta': { 'type': 'number', 'default': 0 },
|
||||
'radius': { 'type': 'number', 'default': 0 },
|
||||
'dx': { 'type': 'number', 'default': 0 },
|
||||
'dy': { 'type': 'number', 'default': 0 },
|
||||
'font': { 'type': 'string', 'default': 'sans-serif' },
|
||||
'fontSize': { 'type': 'number' },
|
||||
'fontStyle': {
|
||||
'enum': [ 'normal', 'italic', 'oblique' ],
|
||||
'default': 'normal'
|
||||
},
|
||||
'fontWeight': {
|
||||
'enum': TEXT_FONT_WEIGHT,
|
||||
'default': 'normal'
|
||||
},
|
||||
'fontVariant': {
|
||||
'enum': [ 'normal', 'small-caps' ],
|
||||
'default': 'normal'
|
||||
}
|
||||
}
|
||||
},
|
||||
'trail': {
|
||||
'properties': {
|
||||
'defined': { 'type': 'boolean' },
|
||||
'size': { 'type': 'number', 'default': 1 }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const schema = build(true);
|
||||
process.stdout.write(JSON.stringify(schema, null, 2));
|
||||
178
node_modules/vega-scenegraph/src/Bounds.js
generated
vendored
Normal file
178
node_modules/vega-scenegraph/src/Bounds.js
generated
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
export default function Bounds(b) {
|
||||
this.clear();
|
||||
if (b) this.union(b);
|
||||
}
|
||||
|
||||
var prototype = Bounds.prototype;
|
||||
|
||||
prototype.clone = function() {
|
||||
return new Bounds(this);
|
||||
};
|
||||
|
||||
prototype.clear = function() {
|
||||
this.x1 = +Number.MAX_VALUE;
|
||||
this.y1 = +Number.MAX_VALUE;
|
||||
this.x2 = -Number.MAX_VALUE;
|
||||
this.y2 = -Number.MAX_VALUE;
|
||||
return this;
|
||||
};
|
||||
|
||||
prototype.empty = function() {
|
||||
return (
|
||||
this.x1 === +Number.MAX_VALUE &&
|
||||
this.y1 === +Number.MAX_VALUE &&
|
||||
this.x2 === -Number.MAX_VALUE &&
|
||||
this.y2 === -Number.MAX_VALUE
|
||||
);
|
||||
};
|
||||
|
||||
prototype.equals = function(b) {
|
||||
return (
|
||||
this.x1 === b.x1 &&
|
||||
this.y1 === b.y1 &&
|
||||
this.x2 === b.x2 &&
|
||||
this.y2 === b.y2
|
||||
);
|
||||
};
|
||||
|
||||
prototype.set = function(x1, y1, x2, y2) {
|
||||
if (x2 < x1) {
|
||||
this.x2 = x1;
|
||||
this.x1 = x2;
|
||||
} else {
|
||||
this.x1 = x1;
|
||||
this.x2 = x2;
|
||||
}
|
||||
if (y2 < y1) {
|
||||
this.y2 = y1;
|
||||
this.y1 = y2;
|
||||
} else {
|
||||
this.y1 = y1;
|
||||
this.y2 = y2;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
prototype.add = function(x, y) {
|
||||
if (x < this.x1) this.x1 = x;
|
||||
if (y < this.y1) this.y1 = y;
|
||||
if (x > this.x2) this.x2 = x;
|
||||
if (y > this.y2) this.y2 = y;
|
||||
return this;
|
||||
};
|
||||
|
||||
prototype.expand = function(d) {
|
||||
this.x1 -= d;
|
||||
this.y1 -= d;
|
||||
this.x2 += d;
|
||||
this.y2 += d;
|
||||
return this;
|
||||
};
|
||||
|
||||
prototype.round = function() {
|
||||
this.x1 = Math.floor(this.x1);
|
||||
this.y1 = Math.floor(this.y1);
|
||||
this.x2 = Math.ceil(this.x2);
|
||||
this.y2 = Math.ceil(this.y2);
|
||||
return this;
|
||||
};
|
||||
|
||||
prototype.scale = function(s) {
|
||||
this.x1 *= s;
|
||||
this.y1 *= s;
|
||||
this.x2 *= s;
|
||||
this.y2 *= s;
|
||||
return this;
|
||||
};
|
||||
|
||||
prototype.translate = function(dx, dy) {
|
||||
this.x1 += dx;
|
||||
this.x2 += dx;
|
||||
this.y1 += dy;
|
||||
this.y2 += dy;
|
||||
return this;
|
||||
};
|
||||
|
||||
prototype.rotate = function(angle, x, y) {
|
||||
const p = this.rotatedPoints(angle, x, y);
|
||||
return this.clear()
|
||||
.add(p[0], p[1])
|
||||
.add(p[2], p[3])
|
||||
.add(p[4], p[5])
|
||||
.add(p[6], p[7]);
|
||||
};
|
||||
|
||||
prototype.rotatedPoints = function(angle, x, y) {
|
||||
var {x1, y1, x2, y2} = this,
|
||||
cos = Math.cos(angle),
|
||||
sin = Math.sin(angle),
|
||||
cx = x - x*cos + y*sin,
|
||||
cy = y - x*sin - y*cos;
|
||||
|
||||
return [
|
||||
cos*x1 - sin*y1 + cx, sin*x1 + cos*y1 + cy,
|
||||
cos*x1 - sin*y2 + cx, sin*x1 + cos*y2 + cy,
|
||||
cos*x2 - sin*y1 + cx, sin*x2 + cos*y1 + cy,
|
||||
cos*x2 - sin*y2 + cx, sin*x2 + cos*y2 + cy
|
||||
];
|
||||
};
|
||||
|
||||
prototype.union = function(b) {
|
||||
if (b.x1 < this.x1) this.x1 = b.x1;
|
||||
if (b.y1 < this.y1) this.y1 = b.y1;
|
||||
if (b.x2 > this.x2) this.x2 = b.x2;
|
||||
if (b.y2 > this.y2) this.y2 = b.y2;
|
||||
return this;
|
||||
};
|
||||
|
||||
prototype.intersect = function(b) {
|
||||
if (b.x1 > this.x1) this.x1 = b.x1;
|
||||
if (b.y1 > this.y1) this.y1 = b.y1;
|
||||
if (b.x2 < this.x2) this.x2 = b.x2;
|
||||
if (b.y2 < this.y2) this.y2 = b.y2;
|
||||
return this;
|
||||
};
|
||||
|
||||
prototype.encloses = function(b) {
|
||||
return b && (
|
||||
this.x1 <= b.x1 &&
|
||||
this.x2 >= b.x2 &&
|
||||
this.y1 <= b.y1 &&
|
||||
this.y2 >= b.y2
|
||||
);
|
||||
};
|
||||
|
||||
prototype.alignsWith = function(b) {
|
||||
return b && (
|
||||
this.x1 == b.x1 ||
|
||||
this.x2 == b.x2 ||
|
||||
this.y1 == b.y1 ||
|
||||
this.y2 == b.y2
|
||||
);
|
||||
};
|
||||
|
||||
prototype.intersects = function(b) {
|
||||
return b && !(
|
||||
this.x2 < b.x1 ||
|
||||
this.x1 > b.x2 ||
|
||||
this.y2 < b.y1 ||
|
||||
this.y1 > b.y2
|
||||
);
|
||||
};
|
||||
|
||||
prototype.contains = function(x, y) {
|
||||
return !(
|
||||
x < this.x1 ||
|
||||
x > this.x2 ||
|
||||
y < this.y1 ||
|
||||
y > this.y2
|
||||
);
|
||||
};
|
||||
|
||||
prototype.width = function() {
|
||||
return this.x2 - this.x1;
|
||||
};
|
||||
|
||||
prototype.height = function() {
|
||||
return this.y2 - this.y1;
|
||||
};
|
||||
208
node_modules/vega-scenegraph/src/CanvasHandler.js
generated
vendored
Normal file
208
node_modules/vega-scenegraph/src/CanvasHandler.js
generated
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
import Handler from './Handler';
|
||||
import Marks from './marks/index';
|
||||
import {
|
||||
ClickEvent, DragEnterEvent, DragLeaveEvent, DragOverEvent, Events,
|
||||
HrefEvent, MouseDownEvent, MouseMoveEvent, MouseOutEvent, MouseOverEvent,
|
||||
MouseWheelEvent, TooltipHideEvent, TooltipShowEvent,
|
||||
TouchEndEvent, TouchMoveEvent, TouchStartEvent
|
||||
} from './util/events';
|
||||
import point from './util/point';
|
||||
import {domFind} from './util/dom';
|
||||
import {inherits} from 'vega-util';
|
||||
|
||||
export default function CanvasHandler(loader, tooltip) {
|
||||
Handler.call(this, loader, tooltip);
|
||||
this._down = null;
|
||||
this._touch = null;
|
||||
this._first = true;
|
||||
this._events = {};
|
||||
}
|
||||
|
||||
const prototype = inherits(CanvasHandler, Handler);
|
||||
|
||||
prototype.initialize = function(el, origin, obj) {
|
||||
this._canvas = el && domFind(el, 'canvas');
|
||||
|
||||
// add minimal events required for proper state management
|
||||
[ClickEvent, MouseDownEvent, MouseMoveEvent, MouseOutEvent, DragLeaveEvent]
|
||||
.forEach(type => eventListenerCheck(this, type));
|
||||
|
||||
return Handler.prototype.initialize.call(this, el, origin, obj);
|
||||
};
|
||||
|
||||
const eventBundle = type => (
|
||||
type === TouchStartEvent ||
|
||||
type === TouchMoveEvent ||
|
||||
type === TouchEndEvent
|
||||
)
|
||||
? [TouchStartEvent, TouchMoveEvent, TouchEndEvent]
|
||||
: [type];
|
||||
|
||||
// lazily add listeners to the canvas as needed
|
||||
function eventListenerCheck(handler, type) {
|
||||
eventBundle(type).forEach(_ => addEventListener(handler, _));
|
||||
}
|
||||
|
||||
function addEventListener(handler, type) {
|
||||
const canvas = handler.canvas();
|
||||
if (canvas && !handler._events[type]) {
|
||||
handler._events[type] = 1;
|
||||
canvas.addEventListener(type, handler[type]
|
||||
? evt => handler[type](evt)
|
||||
: evt => handler.fire(type, evt)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// return the backing canvas instance
|
||||
prototype.canvas = function() {
|
||||
return this._canvas;
|
||||
};
|
||||
|
||||
// retrieve the current canvas context
|
||||
prototype.context = function() {
|
||||
return this._canvas.getContext('2d');
|
||||
};
|
||||
|
||||
// supported events
|
||||
prototype.events = Events;
|
||||
|
||||
function move(moveEvent, overEvent, outEvent) {
|
||||
return function(evt) {
|
||||
const a = this._active,
|
||||
p = this.pickEvent(evt);
|
||||
|
||||
if (p === a) {
|
||||
// active item and picked item are the same
|
||||
this.fire(moveEvent, evt); // fire move
|
||||
} else {
|
||||
// active item and picked item are different
|
||||
if (!a || !a.exit) {
|
||||
// fire out for prior active item
|
||||
// suppress if active item was removed from scene
|
||||
this.fire(outEvent, evt);
|
||||
}
|
||||
this._active = p; // set new active item
|
||||
this.fire(overEvent, evt); // fire over for new active item
|
||||
this.fire(moveEvent, evt); // fire move for new active item
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function inactive(type) {
|
||||
return function(evt) {
|
||||
this.fire(type, evt);
|
||||
this._active = null;
|
||||
};
|
||||
}
|
||||
|
||||
// to keep old versions of firefox happy
|
||||
prototype.DOMMouseScroll = function(evt) {
|
||||
this.fire(MouseWheelEvent, evt);
|
||||
};
|
||||
|
||||
prototype.mousemove = move(MouseMoveEvent, MouseOverEvent, MouseOutEvent);
|
||||
prototype.dragover = move(DragOverEvent, DragEnterEvent, DragLeaveEvent);
|
||||
|
||||
prototype.mouseout = inactive(MouseOutEvent);
|
||||
prototype.dragleave = inactive(DragLeaveEvent);
|
||||
|
||||
prototype.mousedown = function(evt) {
|
||||
this._down = this._active;
|
||||
this.fire(MouseDownEvent, evt);
|
||||
};
|
||||
|
||||
prototype.click = function(evt) {
|
||||
if (this._down === this._active) {
|
||||
this.fire(ClickEvent, evt);
|
||||
this._down = null;
|
||||
}
|
||||
};
|
||||
|
||||
prototype.touchstart = function(evt) {
|
||||
this._touch = this.pickEvent(evt.changedTouches[0]);
|
||||
|
||||
if (this._first) {
|
||||
this._active = this._touch;
|
||||
this._first = false;
|
||||
}
|
||||
|
||||
this.fire(TouchStartEvent, evt, true);
|
||||
};
|
||||
|
||||
prototype.touchmove = function(evt) {
|
||||
this.fire(TouchMoveEvent, evt, true);
|
||||
};
|
||||
|
||||
prototype.touchend = function(evt) {
|
||||
this.fire(TouchEndEvent, evt, true);
|
||||
this._touch = null;
|
||||
};
|
||||
|
||||
// fire an event
|
||||
prototype.fire = function(type, evt, touch) {
|
||||
const a = touch ? this._touch : this._active,
|
||||
h = this._handlers[type];
|
||||
|
||||
// set event type relative to scenegraph items
|
||||
evt.vegaType = type;
|
||||
|
||||
// handle hyperlinks and tooltips first
|
||||
if (type === HrefEvent && a && a.href) {
|
||||
this.handleHref(evt, a, a.href);
|
||||
} else if (type === TooltipShowEvent || type === TooltipHideEvent) {
|
||||
this.handleTooltip(evt, a, type !== TooltipHideEvent);
|
||||
}
|
||||
|
||||
// invoke all registered handlers
|
||||
if (h) {
|
||||
for (let i=0, len=h.length; i<len; ++i) {
|
||||
h[i].handler.call(this._obj, evt, a);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// add an event handler
|
||||
prototype.on = function(type, handler) {
|
||||
const name = this.eventName(type),
|
||||
h = this._handlers,
|
||||
i = this._handlerIndex(h[name], type, handler);
|
||||
|
||||
if (i < 0) {
|
||||
eventListenerCheck(this, type);
|
||||
(h[name] || (h[name] = [])).push({
|
||||
type: type,
|
||||
handler: handler
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// remove an event handler
|
||||
prototype.off = function(type, handler) {
|
||||
const name = this.eventName(type),
|
||||
h = this._handlers[name],
|
||||
i = this._handlerIndex(h, type, handler);
|
||||
|
||||
if (i >= 0) {
|
||||
h.splice(i, 1);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
prototype.pickEvent = function(evt) {
|
||||
const p = point(evt, this._canvas),
|
||||
o = this._origin;
|
||||
return this.pick(this._scene, p[0], p[1], p[0] - o[0], p[1] - o[1]);
|
||||
};
|
||||
|
||||
// find the scenegraph item at the current mouse position
|
||||
// x, y -- the absolute x, y mouse coordinates on the canvas element
|
||||
// gx, gy -- the relative coordinates within the current group
|
||||
prototype.pick = function(scene, x, y, gx, gy) {
|
||||
const g = this.context(),
|
||||
mark = Marks[scene.marktype];
|
||||
return mark.pick.call(this, g, scene, x, y, gx, gy);
|
||||
};
|
||||
149
node_modules/vega-scenegraph/src/CanvasRenderer.js
generated
vendored
Normal file
149
node_modules/vega-scenegraph/src/CanvasRenderer.js
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
import Renderer from './Renderer';
|
||||
import Bounds from './Bounds';
|
||||
import marks from './marks/index';
|
||||
|
||||
import {domClear} from './util/dom';
|
||||
import clip from './util/canvas/clip';
|
||||
import resize from './util/canvas/resize';
|
||||
import {canvas} from 'vega-canvas';
|
||||
import {error, inherits} from 'vega-util';
|
||||
|
||||
export default function CanvasRenderer(loader) {
|
||||
Renderer.call(this, loader);
|
||||
this._options = {};
|
||||
this._redraw = false;
|
||||
this._dirty = new Bounds();
|
||||
this._tempb = new Bounds();
|
||||
}
|
||||
|
||||
const prototype = inherits(CanvasRenderer, Renderer),
|
||||
base = Renderer.prototype;
|
||||
|
||||
prototype.initialize = function(el, width, height, origin, scaleFactor, options) {
|
||||
this._options = options || {};
|
||||
|
||||
this._canvas = this._options.externalContext
|
||||
? null
|
||||
: canvas(1, 1, this._options.type); // instantiate a small canvas
|
||||
|
||||
if (el && this._canvas) {
|
||||
domClear(el, 0).appendChild(this._canvas);
|
||||
this._canvas.setAttribute('class', 'marks');
|
||||
}
|
||||
|
||||
// this method will invoke resize to size the canvas appropriately
|
||||
return base.initialize.call(this, el, width, height, origin, scaleFactor);
|
||||
};
|
||||
|
||||
prototype.resize = function(width, height, origin, scaleFactor) {
|
||||
base.resize.call(this, width, height, origin, scaleFactor);
|
||||
|
||||
if (this._canvas) {
|
||||
// configure canvas size and transform
|
||||
resize(this._canvas, this._width, this._height,
|
||||
this._origin, this._scale, this._options.context);
|
||||
} else {
|
||||
// external context needs to be scaled and positioned to origin
|
||||
const ctx = this._options.externalContext;
|
||||
if (!ctx) error('CanvasRenderer is missing a valid canvas or context');
|
||||
ctx.scale(this._scale, this._scale);
|
||||
ctx.translate(this._origin[0], this._origin[1]);
|
||||
}
|
||||
|
||||
this._redraw = true;
|
||||
return this;
|
||||
};
|
||||
|
||||
prototype.canvas = function() {
|
||||
return this._canvas;
|
||||
};
|
||||
|
||||
prototype.context = function() {
|
||||
return this._options.externalContext
|
||||
|| (this._canvas ? this._canvas.getContext('2d') : null);
|
||||
};
|
||||
|
||||
prototype.dirty = function(item) {
|
||||
let b = this._tempb.clear().union(item.bounds),
|
||||
g = item.mark.group;
|
||||
|
||||
while (g) {
|
||||
b.translate(g.x || 0, g.y || 0);
|
||||
g = g.mark.group;
|
||||
}
|
||||
|
||||
this._dirty.union(b);
|
||||
};
|
||||
|
||||
function clipToBounds(g, b, origin) {
|
||||
// expand bounds by 1 pixel, then round to pixel boundaries
|
||||
b.expand(1).round();
|
||||
|
||||
// align to base pixel grid in case of non-integer scaling (#2425)
|
||||
if (g.pixelRatio % 1) {
|
||||
b.scale(g.pixelRatio).round().scale(1 / g.pixelRatio);
|
||||
}
|
||||
|
||||
// to avoid artifacts translate if origin has fractional pixels
|
||||
b.translate(-(origin[0] % 1), -(origin[1] % 1));
|
||||
|
||||
// set clip path
|
||||
g.beginPath();
|
||||
g.rect(b.x1, b.y1, b.width(), b.height());
|
||||
g.clip();
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
const viewBounds = (origin, width, height) => new Bounds()
|
||||
.set(0, 0, width, height)
|
||||
.translate(-origin[0], -origin[1]);
|
||||
|
||||
prototype._render = function(scene) {
|
||||
const g = this.context(),
|
||||
o = this._origin,
|
||||
w = this._width,
|
||||
h = this._height,
|
||||
db = this._dirty,
|
||||
vb = viewBounds(o, w, h);
|
||||
|
||||
// setup
|
||||
g.save();
|
||||
const b = this._redraw || db.empty()
|
||||
? (this._redraw = false, vb.expand(1))
|
||||
: clipToBounds(g, vb.intersect(db), o);
|
||||
|
||||
this.clear(-o[0], -o[1], w, h);
|
||||
|
||||
// render
|
||||
this.draw(g, scene, b);
|
||||
|
||||
// takedown
|
||||
g.restore();
|
||||
db.clear();
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
prototype.draw = function(ctx, scene, bounds) {
|
||||
const mark = marks[scene.marktype];
|
||||
if (scene.clip) clip(ctx, scene);
|
||||
mark.draw.call(this, ctx, scene, bounds);
|
||||
if (scene.clip) ctx.restore();
|
||||
};
|
||||
|
||||
prototype.clear = function(x, y, w, h) {
|
||||
const opt = this._options,
|
||||
g = this.context();
|
||||
|
||||
if (opt.type !== 'pdf' && !opt.externalContext) {
|
||||
// calling clear rect voids vector output in pdf mode
|
||||
// and could remove external context content (#2615)
|
||||
g.clearRect(x, y, w, h);
|
||||
}
|
||||
|
||||
if (this._bgcolor != null) {
|
||||
g.fillStyle = this._bgcolor;
|
||||
g.fillRect(x, y, w, h);
|
||||
}
|
||||
};
|
||||
62
node_modules/vega-scenegraph/src/Gradient.js
generated
vendored
Normal file
62
node_modules/vega-scenegraph/src/Gradient.js
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
var gradient_id = 0;
|
||||
|
||||
export function resetSVGGradientId() {
|
||||
gradient_id = 0;
|
||||
}
|
||||
|
||||
export const patternPrefix = 'p_';
|
||||
|
||||
export function isGradient(value) {
|
||||
return value && value.gradient;
|
||||
}
|
||||
|
||||
export function gradientRef(g, defs, base) {
|
||||
let id = g.id,
|
||||
type = g.gradient,
|
||||
prefix = type === 'radial' ? patternPrefix : '';
|
||||
|
||||
// check id, assign default values as needed
|
||||
if (!id) {
|
||||
id = g.id = 'gradient_' + (gradient_id++);
|
||||
if (type === 'radial') {
|
||||
g.x1 = get(g.x1, 0.5);
|
||||
g.y1 = get(g.y1, 0.5);
|
||||
g.r1 = get(g.r1, 0);
|
||||
g.x2 = get(g.x2, 0.5);
|
||||
g.y2 = get(g.y2, 0.5);
|
||||
g.r2 = get(g.r2, 0.5);
|
||||
prefix = patternPrefix;
|
||||
} else {
|
||||
g.x1 = get(g.x1, 0);
|
||||
g.y1 = get(g.y1, 0);
|
||||
g.x2 = get(g.x2, 1);
|
||||
g.y2 = get(g.y2, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// register definition
|
||||
defs[id] = g;
|
||||
|
||||
// return url reference
|
||||
return 'url(' + (base || '') + '#' + prefix + id + ')';
|
||||
}
|
||||
|
||||
function get(val, def) {
|
||||
return val != null ? val : def;
|
||||
}
|
||||
|
||||
export default function(p0, p1) {
|
||||
var stops = [], gradient;
|
||||
return gradient = {
|
||||
gradient: 'linear',
|
||||
x1: p0 ? p0[0] : 0,
|
||||
y1: p0 ? p0[1] : 0,
|
||||
x2: p1 ? p1[0] : 1,
|
||||
y2: p1 ? p1[1] : 0,
|
||||
stops: stops,
|
||||
stop: function(offset, color) {
|
||||
stops.push({offset: offset, color: color});
|
||||
return gradient;
|
||||
}
|
||||
};
|
||||
}
|
||||
9
node_modules/vega-scenegraph/src/GroupItem.js
generated
vendored
Normal file
9
node_modules/vega-scenegraph/src/GroupItem.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import Item from './Item';
|
||||
import {inherits} from 'vega-util';
|
||||
|
||||
export default function GroupItem(mark) {
|
||||
Item.call(this, mark);
|
||||
this.items = (this.items || []);
|
||||
}
|
||||
|
||||
inherits(GroupItem, Item);
|
||||
202
node_modules/vega-scenegraph/src/Handler.js
generated
vendored
Normal file
202
node_modules/vega-scenegraph/src/Handler.js
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
import {domCreate} from './util/dom';
|
||||
import resolveItem from './util/resolveItem';
|
||||
import {loader} from 'vega-loader';
|
||||
|
||||
/**
|
||||
* Create a new Handler instance.
|
||||
* @param {object} [customLoader] - Optional loader instance for
|
||||
* href URL sanitization. If not specified, a standard loader
|
||||
* instance will be generated.
|
||||
* @param {function} [customTooltip] - Optional tooltip handler
|
||||
* function for custom tooltip display.
|
||||
* @constructor
|
||||
*/
|
||||
export default function Handler(customLoader, customTooltip) {
|
||||
this._active = null;
|
||||
this._handlers = {};
|
||||
this._loader = customLoader || loader();
|
||||
this._tooltip = customTooltip || defaultTooltip;
|
||||
}
|
||||
|
||||
// The default tooltip display handler.
|
||||
// Sets the HTML title attribute on the visualization container.
|
||||
function defaultTooltip(handler, event, item, value) {
|
||||
handler.element().setAttribute('title', value || '');
|
||||
}
|
||||
|
||||
const prototype = Handler.prototype;
|
||||
|
||||
/**
|
||||
* Initialize a new Handler instance.
|
||||
* @param {DOMElement} el - The containing DOM element for the display.
|
||||
* @param {Array<number>} origin - The origin of the display, in pixels.
|
||||
* The coordinate system will be translated to this point.
|
||||
* @param {object} [obj] - Optional context object that should serve as
|
||||
* the "this" context for event callbacks.
|
||||
* @return {Handler} - This handler instance.
|
||||
*/
|
||||
prototype.initialize = function(el, origin, obj) {
|
||||
this._el = el;
|
||||
this._obj = obj || null;
|
||||
return this.origin(origin);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the parent container element for a visualization.
|
||||
* @return {DOMElement} - The containing DOM element.
|
||||
*/
|
||||
prototype.element = function() {
|
||||
return this._el;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the scene element (e.g., canvas or SVG) of the visualization
|
||||
* Subclasses must override if the first child is not the scene element.
|
||||
* @return {DOMElement} - The scene (e.g., canvas or SVG) element.
|
||||
*/
|
||||
prototype.canvas = function() {
|
||||
return this._el && this._el.firstChild;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get / set the origin coordinates of the visualization.
|
||||
*/
|
||||
prototype.origin = function(origin) {
|
||||
if (arguments.length) {
|
||||
this._origin = origin || [0, 0];
|
||||
return this;
|
||||
} else {
|
||||
return this._origin.slice();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get / set the scenegraph root.
|
||||
*/
|
||||
prototype.scene = function(scene) {
|
||||
if (!arguments.length) return this._scene;
|
||||
this._scene = scene;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add an event handler. Subclasses should override this method.
|
||||
*/
|
||||
prototype.on = function(/*type, handler*/) {};
|
||||
|
||||
/**
|
||||
* Remove an event handler. Subclasses should override this method.
|
||||
*/
|
||||
prototype.off = function(/*type, handler*/) {};
|
||||
|
||||
/**
|
||||
* Utility method for finding the array index of an event handler.
|
||||
* @param {Array} h - An array of registered event handlers.
|
||||
* @param {string} type - The event type.
|
||||
* @param {function} handler - The event handler instance to find.
|
||||
* @return {number} - The handler's array index or -1 if not registered.
|
||||
*/
|
||||
prototype._handlerIndex = function(h, type, handler) {
|
||||
for (let i = h ? h.length : 0; --i>=0;) {
|
||||
if (h[i].type === type && (!handler || h[i].handler === handler)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an array with registered event handlers.
|
||||
* @param {string} [type] - The event type to query. Any annotations
|
||||
* are ignored; for example, for the argument "click.foo", ".foo" will
|
||||
* be ignored and the method returns all "click" handlers. If type is
|
||||
* null or unspecified, this method returns handlers for all types.
|
||||
* @return {Array} - A new array containing all registered event handlers.
|
||||
*/
|
||||
prototype.handlers = function(type) {
|
||||
const h = this._handlers, a = [];
|
||||
if (type) {
|
||||
a.push.apply(a, h[this.eventName(type)]);
|
||||
} else {
|
||||
for (const k in h) { a.push.apply(a, h[k]); }
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses an event name string to return the specific event type.
|
||||
* For example, given "click.foo" returns "click"
|
||||
* @param {string} name - The input event type string.
|
||||
* @return {string} - A string with the event type only.
|
||||
*/
|
||||
prototype.eventName = function(name) {
|
||||
const i = name.indexOf('.');
|
||||
return i < 0 ? name : name.slice(0, i);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle hyperlink navigation in response to an item.href value.
|
||||
* @param {Event} event - The event triggering hyperlink navigation.
|
||||
* @param {Item} item - The scenegraph item.
|
||||
* @param {string} href - The URL to navigate to.
|
||||
*/
|
||||
prototype.handleHref = function(event, item, href) {
|
||||
this._loader
|
||||
.sanitize(href, {context:'href'})
|
||||
.then(opt => {
|
||||
const e = new MouseEvent(event.type, event),
|
||||
a = domCreate(null, 'a');
|
||||
for (const name in opt) a.setAttribute(name, opt[name]);
|
||||
a.dispatchEvent(e);
|
||||
})
|
||||
.catch(function() { /* do nothing */ });
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle tooltip display in response to an item.tooltip value.
|
||||
* @param {Event} event - The event triggering tooltip display.
|
||||
* @param {Item} item - The scenegraph item.
|
||||
* @param {boolean} show - A boolean flag indicating whether
|
||||
* to show or hide a tooltip for the given item.
|
||||
*/
|
||||
prototype.handleTooltip = function(event, item, show) {
|
||||
if (item && item.tooltip != null) {
|
||||
item = resolveItem(item, event, this.canvas(), this._origin);
|
||||
const value = (show && item && item.tooltip) || null;
|
||||
this._tooltip.call(this._obj, this, event, item, value);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the size of a scenegraph item and its position relative
|
||||
* to the viewport.
|
||||
* @param {Item} item - The scenegraph item.
|
||||
* @return {object} - A bounding box object (compatible with the
|
||||
* DOMRect type) consisting of x, y, width, heigh, top, left,
|
||||
* right, and bottom properties.
|
||||
*/
|
||||
prototype.getItemBoundingClientRect = function(item) {
|
||||
const el = this.canvas();
|
||||
if (!el) return;
|
||||
|
||||
const rect = el.getBoundingClientRect(),
|
||||
origin = this._origin,
|
||||
bounds = item.bounds,
|
||||
width = bounds.width(),
|
||||
height = bounds.height();
|
||||
|
||||
let x = bounds.x1 + origin[0] + rect.left,
|
||||
y = bounds.y1 + origin[1] + rect.top;
|
||||
|
||||
// translate coordinate for each parent group
|
||||
while (item.mark && (item = item.mark.group)) {
|
||||
x += item.x || 0;
|
||||
y += item.y || 0;
|
||||
}
|
||||
|
||||
// return DOMRect-compatible bounding box
|
||||
return {
|
||||
x, y, width, height,
|
||||
left: x, top: y, right: x + width, bottom: y + height
|
||||
};
|
||||
};
|
||||
6
node_modules/vega-scenegraph/src/Item.js
generated
vendored
Normal file
6
node_modules/vega-scenegraph/src/Item.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import Bounds from './Bounds';
|
||||
|
||||
export default function Item(mark) {
|
||||
this.mark = mark;
|
||||
this.bounds = (this.bounds || new Bounds());
|
||||
}
|
||||
183
node_modules/vega-scenegraph/src/Renderer.js
generated
vendored
Normal file
183
node_modules/vega-scenegraph/src/Renderer.js
generated
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
import ResourceLoader from './ResourceLoader';
|
||||
|
||||
/**
|
||||
* Create a new Renderer instance.
|
||||
* @param {object} [loader] - Optional loader instance for
|
||||
* image and href URL sanitization. If not specified, a
|
||||
* standard loader instance will be generated.
|
||||
* @constructor
|
||||
*/
|
||||
export default function Renderer(loader) {
|
||||
this._el = null;
|
||||
this._bgcolor = null;
|
||||
this._loader = new ResourceLoader(loader);
|
||||
}
|
||||
|
||||
var prototype = Renderer.prototype;
|
||||
|
||||
/**
|
||||
* Initialize a new Renderer instance.
|
||||
* @param {DOMElement} el - The containing DOM element for the display.
|
||||
* @param {number} width - The coordinate width of the display, in pixels.
|
||||
* @param {number} height - The coordinate height of the display, in pixels.
|
||||
* @param {Array<number>} origin - The origin of the display, in pixels.
|
||||
* The coordinate system will be translated to this point.
|
||||
* @param {number} [scaleFactor=1] - Optional scaleFactor by which to multiply
|
||||
* the width and height to determine the final pixel size.
|
||||
* @return {Renderer} - This renderer instance.
|
||||
*/
|
||||
prototype.initialize = function(el, width, height, origin, scaleFactor) {
|
||||
this._el = el;
|
||||
return this.resize(width, height, origin, scaleFactor);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the parent container element for a visualization.
|
||||
* @return {DOMElement} - The containing DOM element.
|
||||
*/
|
||||
prototype.element = function() {
|
||||
return this._el;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the scene element (e.g., canvas or SVG) of the visualization
|
||||
* Subclasses must override if the first child is not the scene element.
|
||||
* @return {DOMElement} - The scene (e.g., canvas or SVG) element.
|
||||
*/
|
||||
prototype.canvas = function() {
|
||||
return this._el && this._el.firstChild;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get / set the background color.
|
||||
*/
|
||||
prototype.background = function(bgcolor) {
|
||||
if (arguments.length === 0) return this._bgcolor;
|
||||
this._bgcolor = bgcolor;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resize the display.
|
||||
* @param {number} width - The new coordinate width of the display, in pixels.
|
||||
* @param {number} height - The new coordinate height of the display, in pixels.
|
||||
* @param {Array<number>} origin - The new origin of the display, in pixels.
|
||||
* The coordinate system will be translated to this point.
|
||||
* @param {number} [scaleFactor=1] - Optional scaleFactor by which to multiply
|
||||
* the width and height to determine the final pixel size.
|
||||
* @return {Renderer} - This renderer instance;
|
||||
*/
|
||||
prototype.resize = function(width, height, origin, scaleFactor) {
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
this._origin = origin || [0, 0];
|
||||
this._scale = scaleFactor || 1;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Report a dirty item whose bounds should be redrawn.
|
||||
* This base class method does nothing. Subclasses that perform
|
||||
* incremental should implement this method.
|
||||
* @param {Item} item - The dirty item whose bounds should be redrawn.
|
||||
*/
|
||||
prototype.dirty = function(/*item*/) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Render an input scenegraph, potentially with a set of dirty items.
|
||||
* This method will perform an immediate rendering with available resources.
|
||||
* The renderer may also need to perform image loading to perform a complete
|
||||
* render. This process can lead to asynchronous re-rendering of the scene
|
||||
* after this method returns. To receive notification when rendering is
|
||||
* complete, use the renderAsync method instead.
|
||||
* @param {object} scene - The root mark of a scenegraph to render.
|
||||
* @return {Renderer} - This renderer instance.
|
||||
*/
|
||||
prototype.render = function(scene) {
|
||||
var r = this;
|
||||
|
||||
// bind arguments into a render call, and cache it
|
||||
// this function may be subsequently called for async redraw
|
||||
r._call = function() { r._render(scene); };
|
||||
|
||||
// invoke the renderer
|
||||
r._call();
|
||||
|
||||
// clear the cached call for garbage collection
|
||||
// async redraws will stash their own copy
|
||||
r._call = null;
|
||||
|
||||
return r;
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal rendering method. Renderer subclasses should override this
|
||||
* method to actually perform rendering.
|
||||
* @param {object} scene - The root mark of a scenegraph to render.
|
||||
*/
|
||||
prototype._render = function(/*scene*/) {
|
||||
// subclasses to override
|
||||
};
|
||||
|
||||
/**
|
||||
* Asynchronous rendering method. Similar to render, but returns a Promise
|
||||
* that resolves when all rendering is completed. Sometimes a renderer must
|
||||
* perform image loading to get a complete rendering. The returned
|
||||
* Promise will not resolve until this process completes.
|
||||
* @param {object} scene - The root mark of a scenegraph to render.
|
||||
* @return {Promise} - A Promise that resolves when rendering is complete.
|
||||
*/
|
||||
prototype.renderAsync = function(scene) {
|
||||
var r = this.render(scene);
|
||||
return this._ready
|
||||
? this._ready.then(function() { return r; })
|
||||
: Promise.resolve(r);
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal method for asynchronous resource loading.
|
||||
* Proxies method calls to the ImageLoader, and tracks loading
|
||||
* progress to invoke a re-render once complete.
|
||||
* @param {string} method - The method name to invoke on the ImageLoader.
|
||||
* @param {string} uri - The URI for the requested resource.
|
||||
* @return {Promise} - A Promise that resolves to the requested resource.
|
||||
*/
|
||||
prototype._load = function(method, uri) {
|
||||
var r = this,
|
||||
p = r._loader[method](uri);
|
||||
|
||||
if (!r._ready) {
|
||||
// re-render the scene when loading completes
|
||||
var call = r._call;
|
||||
r._ready = r._loader.ready()
|
||||
.then(function(redraw) {
|
||||
if (redraw) call();
|
||||
r._ready = null;
|
||||
});
|
||||
}
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sanitize a URL to include as a hyperlink in the rendered scene.
|
||||
* This method proxies a call to ImageLoader.sanitizeURL, but also tracks
|
||||
* image loading progress and invokes a re-render once complete.
|
||||
* @param {string} uri - The URI string to sanitize.
|
||||
* @return {Promise} - A Promise that resolves to the sanitized URL.
|
||||
*/
|
||||
prototype.sanitizeURL = function(uri) {
|
||||
return this._load('sanitizeURL', uri);
|
||||
};
|
||||
|
||||
/**
|
||||
* Requests an image to include in the rendered scene.
|
||||
* This method proxies a call to ImageLoader.loadImage, but also tracks
|
||||
* image loading progress and invokes a re-render once complete.
|
||||
* @param {string} uri - The URI string of the image.
|
||||
* @return {Promise} - A Promise that resolves to the loaded Image.
|
||||
*/
|
||||
prototype.loadImage = function(uri) {
|
||||
return this._load('loadImage', uri);
|
||||
};
|
||||
79
node_modules/vega-scenegraph/src/ResourceLoader.js
generated
vendored
Normal file
79
node_modules/vega-scenegraph/src/ResourceLoader.js
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
import {image} from 'vega-canvas';
|
||||
import {loader} from 'vega-loader';
|
||||
import {hasOwnProperty} from 'vega-util';
|
||||
|
||||
export default function ResourceLoader(customLoader) {
|
||||
this._pending = 0;
|
||||
this._loader = customLoader || loader();
|
||||
}
|
||||
|
||||
var prototype = ResourceLoader.prototype;
|
||||
|
||||
prototype.pending = function() {
|
||||
return this._pending;
|
||||
};
|
||||
|
||||
function increment(loader) {
|
||||
loader._pending += 1;
|
||||
}
|
||||
|
||||
function decrement(loader) {
|
||||
loader._pending -= 1;
|
||||
}
|
||||
|
||||
prototype.sanitizeURL = function(uri) {
|
||||
var loader = this;
|
||||
increment(loader);
|
||||
|
||||
return loader._loader.sanitize(uri, {context:'href'})
|
||||
.then(function(opt) {
|
||||
decrement(loader);
|
||||
return opt;
|
||||
})
|
||||
.catch(function() {
|
||||
decrement(loader);
|
||||
return null;
|
||||
});
|
||||
};
|
||||
|
||||
prototype.loadImage = function(uri) {
|
||||
const loader = this,
|
||||
Image = image();
|
||||
increment(loader);
|
||||
|
||||
return loader._loader
|
||||
.sanitize(uri, {context: 'image'})
|
||||
.then(function(opt) {
|
||||
const url = opt.href;
|
||||
if (!url || !Image) throw {url: url};
|
||||
|
||||
const img = new Image();
|
||||
|
||||
// set crossOrigin only if cors is defined; empty string sets anonymous mode
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/crossOrigin
|
||||
const cors = hasOwnProperty(opt, 'crossOrigin') ? opt.crossOrigin : 'anonymous';
|
||||
if (cors != null) img.crossOrigin = cors;
|
||||
|
||||
// attempt to load image resource
|
||||
img.onload = () => decrement(loader);
|
||||
img.onerror = () => decrement(loader);
|
||||
img.src = url;
|
||||
|
||||
return img;
|
||||
})
|
||||
.catch(function(e) {
|
||||
decrement(loader);
|
||||
return {complete: false, width: 0, height: 0, src: e && e.url || ''};
|
||||
});
|
||||
};
|
||||
|
||||
prototype.ready = function() {
|
||||
var loader = this;
|
||||
return new Promise(function(accept) {
|
||||
function poll(value) {
|
||||
if (!loader.pending()) accept(value);
|
||||
else setTimeout(function() { poll(true); }, 10);
|
||||
}
|
||||
poll(false);
|
||||
});
|
||||
};
|
||||
83
node_modules/vega-scenegraph/src/SVGHandler.js
generated
vendored
Normal file
83
node_modules/vega-scenegraph/src/SVGHandler.js
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
import Handler from './Handler';
|
||||
import {domFind} from './util/dom';
|
||||
import {HrefEvent, TooltipHideEvent, TooltipShowEvent} from './util/events';
|
||||
import {inherits} from 'vega-util';
|
||||
|
||||
export default function SVGHandler(loader, tooltip) {
|
||||
Handler.call(this, loader, tooltip);
|
||||
const h = this;
|
||||
h._hrefHandler = listener(h, (evt, item) => {
|
||||
if (item && item.href) h.handleHref(evt, item, item.href);
|
||||
});
|
||||
h._tooltipHandler = listener(h, (evt, item) => {
|
||||
h.handleTooltip(evt, item, evt.type !== TooltipHideEvent);
|
||||
});
|
||||
}
|
||||
|
||||
const prototype = inherits(SVGHandler, Handler);
|
||||
|
||||
prototype.initialize = function(el, origin, obj) {
|
||||
let svg = this._svg;
|
||||
if (svg) {
|
||||
svg.removeEventListener(HrefEvent, this._hrefHandler);
|
||||
svg.removeEventListener(TooltipShowEvent, this._tooltipHandler);
|
||||
svg.removeEventListener(TooltipHideEvent, this._tooltipHandler);
|
||||
}
|
||||
this._svg = svg = el && domFind(el, 'svg');
|
||||
if (svg) {
|
||||
svg.addEventListener(HrefEvent, this._hrefHandler);
|
||||
svg.addEventListener(TooltipShowEvent, this._tooltipHandler);
|
||||
svg.addEventListener(TooltipHideEvent, this._tooltipHandler);
|
||||
}
|
||||
return Handler.prototype.initialize.call(this, el, origin, obj);
|
||||
};
|
||||
|
||||
prototype.canvas = function() {
|
||||
return this._svg;
|
||||
};
|
||||
|
||||
// wrap an event listener for the SVG DOM
|
||||
const listener = (context, handler) => evt => {
|
||||
let item = evt.target.__data__;
|
||||
item = Array.isArray(item) ? item[0] : item;
|
||||
evt.vegaType = evt.type;
|
||||
handler.call(context._obj, evt, item);
|
||||
};
|
||||
|
||||
// add an event handler
|
||||
prototype.on = function(type, handler) {
|
||||
const name = this.eventName(type),
|
||||
h = this._handlers,
|
||||
i = this._handlerIndex(h[name], type, handler);
|
||||
|
||||
if (i < 0) {
|
||||
const x = {
|
||||
type,
|
||||
handler,
|
||||
listener: listener(this, handler)
|
||||
};
|
||||
|
||||
(h[name] || (h[name] = [])).push(x);
|
||||
if (this._svg) {
|
||||
this._svg.addEventListener(name, x.listener);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// remove an event handler
|
||||
prototype.off = function(type, handler) {
|
||||
const name = this.eventName(type),
|
||||
h = this._handlers[name],
|
||||
i = this._handlerIndex(h, type, handler);
|
||||
|
||||
if (i >= 0) {
|
||||
if (this._svg) {
|
||||
this._svg.removeEventListener(name, h[i].listener);
|
||||
}
|
||||
h.splice(i, 1);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
613
node_modules/vega-scenegraph/src/SVGRenderer.js
generated
vendored
Normal file
613
node_modules/vega-scenegraph/src/SVGRenderer.js
generated
vendored
Normal file
@@ -0,0 +1,613 @@
|
||||
import Renderer from './Renderer';
|
||||
import {gradientRef, isGradient, patternPrefix} from './Gradient';
|
||||
import marks from './marks/index';
|
||||
import {ariaItemAttributes, ariaMarkAttributes} from './util/aria';
|
||||
import {cssClass, domChild, domClear, domCreate} from './util/dom';
|
||||
import {closeTag, openTag} from './util/tags';
|
||||
import {fontFamily, fontSize, lineHeight, textLines, textValue} from './util/text';
|
||||
import {visit} from './util/visit';
|
||||
import clip from './util/svg/clip';
|
||||
import metadata from './util/svg/metadata';
|
||||
import {rootAttributes, styles} from './util/svg/styles';
|
||||
import {inherits, isArray} from 'vega-util';
|
||||
|
||||
const RootIndex = 0,
|
||||
ns = metadata.xmlns;
|
||||
|
||||
export default function SVGRenderer(loader) {
|
||||
Renderer.call(this, loader);
|
||||
this._dirtyID = 0;
|
||||
this._dirty = [];
|
||||
this._svg = null;
|
||||
this._root = null;
|
||||
this._defs = null;
|
||||
}
|
||||
|
||||
var prototype = inherits(SVGRenderer, Renderer);
|
||||
var base = Renderer.prototype;
|
||||
|
||||
prototype.initialize = function(el, width, height, padding) {
|
||||
// create the svg definitions cache
|
||||
this._defs = {
|
||||
gradient: {},
|
||||
clipping: {}
|
||||
};
|
||||
|
||||
if (el) {
|
||||
this._svg = domChild(el, 0, 'svg', ns);
|
||||
this._svg.setAttribute('class', 'marks');
|
||||
domClear(el, 1);
|
||||
|
||||
// set the svg root group
|
||||
this._root = domChild(this._svg, RootIndex, 'g', ns);
|
||||
for (const attr in rootAttributes) {
|
||||
this._root.setAttribute(attr, rootAttributes[attr]);
|
||||
}
|
||||
|
||||
// ensure no additional child elements
|
||||
domClear(this._svg, RootIndex + 1);
|
||||
}
|
||||
|
||||
// set background color if defined
|
||||
this.background(this._bgcolor);
|
||||
|
||||
return base.initialize.call(this, el, width, height, padding);
|
||||
};
|
||||
|
||||
prototype.background = function(bgcolor) {
|
||||
if (arguments.length && this._svg) {
|
||||
this._svg.style.setProperty('background-color', bgcolor);
|
||||
}
|
||||
return base.background.apply(this, arguments);
|
||||
};
|
||||
|
||||
prototype.resize = function(width, height, origin, scaleFactor) {
|
||||
base.resize.call(this, width, height, origin, scaleFactor);
|
||||
|
||||
if (this._svg) {
|
||||
this._svg.setAttribute('width', this._width * this._scale);
|
||||
this._svg.setAttribute('height', this._height * this._scale);
|
||||
this._svg.setAttribute('viewBox', '0 0 ' + this._width + ' ' + this._height);
|
||||
this._root.setAttribute('transform', 'translate(' + this._origin + ')');
|
||||
}
|
||||
|
||||
this._dirty = [];
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
prototype.canvas = function() {
|
||||
return this._svg;
|
||||
};
|
||||
|
||||
prototype.svg = function() {
|
||||
if (!this._svg) return null;
|
||||
|
||||
var attr = {
|
||||
class: 'marks',
|
||||
width: this._width * this._scale,
|
||||
height: this._height * this._scale,
|
||||
viewBox: '0 0 ' + this._width + ' ' + this._height
|
||||
};
|
||||
for (var key in metadata) {
|
||||
attr[key] = metadata[key];
|
||||
}
|
||||
|
||||
var bg = !this._bgcolor ? ''
|
||||
: (openTag('rect', {
|
||||
width: this._width,
|
||||
height: this._height,
|
||||
fill: this._bgcolor
|
||||
}) + closeTag('rect'));
|
||||
|
||||
return openTag('svg', attr)
|
||||
+ (this._defs.el ? this._defs.el.outerHTML : '')
|
||||
+ bg
|
||||
+ this._root.outerHTML
|
||||
+ closeTag('svg');
|
||||
};
|
||||
|
||||
|
||||
// -- Render entry point --
|
||||
|
||||
prototype._render = function(scene) {
|
||||
// perform spot updates and re-render markup
|
||||
if (this._dirtyCheck()) {
|
||||
if (this._dirtyAll) this._resetDefs();
|
||||
this.draw(this._root, scene);
|
||||
domClear(this._root, 1);
|
||||
}
|
||||
|
||||
this.updateDefs();
|
||||
|
||||
this._dirty = [];
|
||||
++this._dirtyID;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// -- Manage SVG definitions ('defs') block --
|
||||
|
||||
prototype.updateDefs = function() {
|
||||
const svg = this._svg,
|
||||
defs = this._defs;
|
||||
|
||||
let el = defs.el,
|
||||
index = 0;
|
||||
|
||||
for (const id in defs.gradient) {
|
||||
if (!el) defs.el = (el = domChild(svg, RootIndex, 'defs', ns));
|
||||
index = updateGradient(el, defs.gradient[id], index);
|
||||
}
|
||||
|
||||
for (const id in defs.clipping) {
|
||||
if (!el) defs.el = (el = domChild(svg, RootIndex, 'defs', ns));
|
||||
index = updateClipping(el, defs.clipping[id], index);
|
||||
}
|
||||
|
||||
// clean-up
|
||||
if (el) {
|
||||
index === 0
|
||||
? (svg.removeChild(el), defs.el = null)
|
||||
: domClear(el, index);
|
||||
}
|
||||
};
|
||||
|
||||
function updateGradient(el, grad, index) {
|
||||
var i, n, stop;
|
||||
|
||||
if (grad.gradient === 'radial') {
|
||||
// SVG radial gradients automatically transform to normalized bbox
|
||||
// coordinates, in a way that is cumbersome to replicate in canvas.
|
||||
// We wrap the radial gradient in a pattern element, allowing us to
|
||||
// maintain a circular gradient that matches what canvas provides.
|
||||
var pt = domChild(el, index++, 'pattern', ns);
|
||||
pt.setAttribute('id', patternPrefix + grad.id);
|
||||
pt.setAttribute('viewBox', '0,0,1,1');
|
||||
pt.setAttribute('width', '100%');
|
||||
pt.setAttribute('height', '100%');
|
||||
pt.setAttribute('preserveAspectRatio', 'xMidYMid slice');
|
||||
|
||||
pt = domChild(pt, 0, 'rect', ns);
|
||||
pt.setAttribute('width', '1');
|
||||
pt.setAttribute('height', '1');
|
||||
pt.setAttribute('fill', 'url(' + href() + '#' + grad.id + ')');
|
||||
|
||||
el = domChild(el, index++, 'radialGradient', ns);
|
||||
el.setAttribute('id', grad.id);
|
||||
el.setAttribute('fx', grad.x1);
|
||||
el.setAttribute('fy', grad.y1);
|
||||
el.setAttribute('fr', grad.r1);
|
||||
el.setAttribute('cx', grad.x2);
|
||||
el.setAttribute('cy', grad.y2);
|
||||
el.setAttribute( 'r', grad.r2);
|
||||
} else {
|
||||
el = domChild(el, index++, 'linearGradient', ns);
|
||||
el.setAttribute('id', grad.id);
|
||||
el.setAttribute('x1', grad.x1);
|
||||
el.setAttribute('x2', grad.x2);
|
||||
el.setAttribute('y1', grad.y1);
|
||||
el.setAttribute('y2', grad.y2);
|
||||
}
|
||||
|
||||
for (i=0, n=grad.stops.length; i<n; ++i) {
|
||||
stop = domChild(el, i, 'stop', ns);
|
||||
stop.setAttribute('offset', grad.stops[i].offset);
|
||||
stop.setAttribute('stop-color', grad.stops[i].color);
|
||||
}
|
||||
domClear(el, i);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
function updateClipping(el, clip, index) {
|
||||
var mask;
|
||||
|
||||
el = domChild(el, index, 'clipPath', ns);
|
||||
el.setAttribute('id', clip.id);
|
||||
|
||||
if (clip.path) {
|
||||
mask = domChild(el, 0, 'path', ns);
|
||||
mask.setAttribute('d', clip.path);
|
||||
} else {
|
||||
mask = domChild(el, 0, 'rect', ns);
|
||||
mask.setAttribute('x', 0);
|
||||
mask.setAttribute('y', 0);
|
||||
mask.setAttribute('width', clip.width);
|
||||
mask.setAttribute('height', clip.height);
|
||||
}
|
||||
domClear(el, 1);
|
||||
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
prototype._resetDefs = function() {
|
||||
var def = this._defs;
|
||||
def.gradient = {};
|
||||
def.clipping = {};
|
||||
};
|
||||
|
||||
|
||||
// -- Manage rendering of items marked as dirty --
|
||||
|
||||
prototype.dirty = function(item) {
|
||||
if (item.dirty !== this._dirtyID) {
|
||||
item.dirty = this._dirtyID;
|
||||
this._dirty.push(item);
|
||||
}
|
||||
};
|
||||
|
||||
prototype.isDirty = function(item) {
|
||||
return this._dirtyAll
|
||||
|| !item._svg
|
||||
|| item.dirty === this._dirtyID;
|
||||
};
|
||||
|
||||
prototype._dirtyCheck = function() {
|
||||
this._dirtyAll = true;
|
||||
var items = this._dirty;
|
||||
if (!items.length || !this._dirtyID) return true;
|
||||
|
||||
var id = ++this._dirtyID,
|
||||
item, mark, type, mdef, i, n, o;
|
||||
|
||||
for (i=0, n=items.length; i<n; ++i) {
|
||||
item = items[i];
|
||||
mark = item.mark;
|
||||
|
||||
if (mark.marktype !== type) {
|
||||
// memoize mark instance lookup
|
||||
type = mark.marktype;
|
||||
mdef = marks[type];
|
||||
}
|
||||
|
||||
if (mark.zdirty && mark.dirty !== id) {
|
||||
this._dirtyAll = false;
|
||||
dirtyParents(item, id);
|
||||
mark.items.forEach(function(i) { i.dirty = id; });
|
||||
}
|
||||
if (mark.zdirty) continue; // handle in standard drawing pass
|
||||
|
||||
if (item.exit) { // EXIT
|
||||
if (mdef.nested && mark.items.length) {
|
||||
// if nested mark with remaining points, update instead
|
||||
o = mark.items[0];
|
||||
if (o._svg) this._update(mdef, o._svg, o);
|
||||
} else if (item._svg) {
|
||||
// otherwise remove from DOM
|
||||
o = item._svg.parentNode;
|
||||
if (o) o.removeChild(item._svg);
|
||||
}
|
||||
item._svg = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
item = (mdef.nested ? mark.items[0] : item);
|
||||
if (item._update === id) continue; // already visited
|
||||
|
||||
if (!item._svg || !item._svg.ownerSVGElement) {
|
||||
// ENTER
|
||||
this._dirtyAll = false;
|
||||
dirtyParents(item, id);
|
||||
} else {
|
||||
// IN-PLACE UPDATE
|
||||
this._update(mdef, item._svg, item);
|
||||
}
|
||||
item._update = id;
|
||||
}
|
||||
return !this._dirtyAll;
|
||||
};
|
||||
|
||||
function dirtyParents(item, id) {
|
||||
for (; item && item.dirty !== id; item=item.mark.group) {
|
||||
item.dirty = id;
|
||||
if (item.mark && item.mark.dirty !== id) {
|
||||
item.mark.dirty = id;
|
||||
} else return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -- Construct & maintain scenegraph to SVG mapping ---
|
||||
|
||||
// Draw a mark container.
|
||||
prototype.draw = function(el, scene, prev) {
|
||||
if (!this.isDirty(scene)) return scene._svg;
|
||||
|
||||
var svg = this._svg,
|
||||
mdef = marks[scene.marktype],
|
||||
events = scene.interactive === false ? 'none' : null,
|
||||
isGroup = mdef.tag === 'g',
|
||||
sibling = null,
|
||||
i = 0,
|
||||
parent;
|
||||
|
||||
parent = bind(scene, el, prev, 'g', svg);
|
||||
parent.setAttribute('class', cssClass(scene));
|
||||
|
||||
// apply aria attributes to parent container element
|
||||
const aria = ariaMarkAttributes(scene);
|
||||
for (const key in aria) setAttribute(parent, key, aria[key]);
|
||||
|
||||
if (!isGroup) {
|
||||
setAttribute(parent, 'pointer-events', events);
|
||||
}
|
||||
setAttribute(parent, 'clip-path',
|
||||
scene.clip ? clip(this, scene, scene.group) : null);
|
||||
|
||||
const process = item => {
|
||||
const dirty = this.isDirty(item),
|
||||
node = bind(item, parent, sibling, mdef.tag, svg);
|
||||
|
||||
if (dirty) {
|
||||
this._update(mdef, node, item);
|
||||
if (isGroup) recurse(this, node, item);
|
||||
}
|
||||
|
||||
sibling = node;
|
||||
++i;
|
||||
};
|
||||
|
||||
if (mdef.nested) {
|
||||
if (scene.items.length) process(scene.items[0]);
|
||||
} else {
|
||||
visit(scene, process);
|
||||
}
|
||||
|
||||
domClear(parent, i);
|
||||
return parent;
|
||||
};
|
||||
|
||||
// Recursively process group contents.
|
||||
function recurse(renderer, el, group) {
|
||||
el = el.lastChild.previousSibling;
|
||||
let prev, idx = 0;
|
||||
|
||||
visit(group, item => {
|
||||
prev = renderer.draw(el, item, prev);
|
||||
++idx;
|
||||
});
|
||||
|
||||
// remove any extraneous DOM elements
|
||||
domClear(el, 1 + idx);
|
||||
}
|
||||
|
||||
// Bind a scenegraph item to an SVG DOM element.
|
||||
// Create new SVG elements as needed.
|
||||
function bind(item, el, sibling, tag, svg) {
|
||||
let node = item._svg, doc;
|
||||
|
||||
// create a new dom node if needed
|
||||
if (!node) {
|
||||
doc = el.ownerDocument;
|
||||
node = domCreate(doc, tag, ns);
|
||||
item._svg = node;
|
||||
|
||||
if (item.mark) {
|
||||
node.__data__ = item;
|
||||
node.__values__ = {fill: 'default'};
|
||||
|
||||
// if group, create background, content, and foreground elements
|
||||
if (tag === 'g') {
|
||||
const bg = domCreate(doc, 'path', ns);
|
||||
node.appendChild(bg);
|
||||
bg.__data__ = item;
|
||||
|
||||
const cg = domCreate(doc, 'g', ns);
|
||||
node.appendChild(cg);
|
||||
cg.__data__ = item;
|
||||
|
||||
const fg = domCreate(doc, 'path', ns);
|
||||
node.appendChild(fg);
|
||||
fg.__data__ = item;
|
||||
fg.__values__ = {fill: 'default'};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// (re-)insert if (a) not contained in SVG or (b) sibling order has changed
|
||||
if (node.ownerSVGElement !== svg || siblingCheck(node, sibling)) {
|
||||
el.insertBefore(node, sibling ? sibling.nextSibling : el.firstChild);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function siblingCheck(node, sibling) {
|
||||
return node.parentNode
|
||||
&& node.parentNode.childNodes.length > 1
|
||||
&& node.previousSibling != sibling; // treat null/undefined the same
|
||||
}
|
||||
|
||||
|
||||
// -- Set attributes & styles on SVG elements ---
|
||||
|
||||
var element = null, // temp var for current SVG element
|
||||
values = null; // temp var for current values hash
|
||||
|
||||
// Extra configuration for certain mark types
|
||||
var mark_extras = {
|
||||
group: function(mdef, el, item) {
|
||||
const fg = element = el.childNodes[2];
|
||||
values = fg.__values__;
|
||||
mdef.foreground(emit, item, this);
|
||||
|
||||
values = el.__values__; // use parent's values hash
|
||||
element = el.childNodes[1];
|
||||
mdef.content(emit, item, this);
|
||||
|
||||
const bg = element = el.childNodes[0];
|
||||
mdef.background(emit, item, this);
|
||||
|
||||
const value = item.mark.interactive === false ? 'none' : null;
|
||||
if (value !== values.events) {
|
||||
setAttribute(fg, 'pointer-events', value);
|
||||
setAttribute(bg, 'pointer-events', value);
|
||||
values.events = value;
|
||||
}
|
||||
|
||||
if (item.strokeForeground && item.stroke) {
|
||||
const fill = item.fill;
|
||||
setAttribute(fg, 'display', null);
|
||||
|
||||
// set style of background
|
||||
this.style(bg, item);
|
||||
setAttribute(bg, 'stroke', null);
|
||||
|
||||
// set style of foreground
|
||||
if (fill) item.fill = null;
|
||||
values = fg.__values__;
|
||||
this.style(fg, item);
|
||||
if (fill) item.fill = fill;
|
||||
|
||||
// leave element null to prevent downstream styling
|
||||
element = null;
|
||||
} else {
|
||||
// ensure foreground is ignored
|
||||
setAttribute(fg, 'display', 'none');
|
||||
}
|
||||
},
|
||||
image: function(mdef, el, item) {
|
||||
if (item.smooth === false) {
|
||||
setStyle(el, 'image-rendering', 'optimizeSpeed');
|
||||
setStyle(el, 'image-rendering', 'pixelated');
|
||||
} else {
|
||||
setStyle(el, 'image-rendering', null);
|
||||
}
|
||||
},
|
||||
text: function(mdef, el, item) {
|
||||
let tl = textLines(item),
|
||||
key, value, doc, lh;
|
||||
|
||||
if (isArray(tl)) {
|
||||
// multi-line text
|
||||
value = tl.map(_ => textValue(item, _));
|
||||
key = value.join('\n'); // content cache key
|
||||
|
||||
if (key !== values.text) {
|
||||
domClear(el, 0);
|
||||
doc = el.ownerDocument;
|
||||
lh = lineHeight(item);
|
||||
value.forEach((t, i) => {
|
||||
const ts = domCreate(doc, 'tspan', ns);
|
||||
ts.__data__ = item; // data binding
|
||||
ts.textContent = t;
|
||||
if (i) {
|
||||
ts.setAttribute('x', 0);
|
||||
ts.setAttribute('dy', lh);
|
||||
}
|
||||
el.appendChild(ts);
|
||||
});
|
||||
values.text = key;
|
||||
}
|
||||
} else {
|
||||
// single-line text
|
||||
value = textValue(item, tl);
|
||||
if (value !== values.text) {
|
||||
el.textContent = value;
|
||||
values.text = value;
|
||||
}
|
||||
}
|
||||
|
||||
setAttribute(el, 'font-family', fontFamily(item));
|
||||
setAttribute(el, 'font-size', fontSize(item) + 'px');
|
||||
setAttribute(el, 'font-style', item.fontStyle);
|
||||
setAttribute(el, 'font-variant', item.fontVariant);
|
||||
setAttribute(el, 'font-weight', item.fontWeight);
|
||||
}
|
||||
};
|
||||
|
||||
function setStyle(el, name, value) {
|
||||
if (value !== values[name]) {
|
||||
if (value == null) {
|
||||
el.style.removeProperty(name);
|
||||
} else {
|
||||
el.style.setProperty(name, value + '');
|
||||
}
|
||||
values[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
prototype._update = function(mdef, el, item) {
|
||||
// set dom element and values cache
|
||||
// provides access to emit method
|
||||
element = el;
|
||||
values = el.__values__;
|
||||
|
||||
// apply aria-specific properties
|
||||
ariaItemAttributes(emit, item);
|
||||
|
||||
// apply svg attributes
|
||||
mdef.attr(emit, item, this);
|
||||
|
||||
// some marks need special treatment
|
||||
const extra = mark_extras[mdef.type];
|
||||
if (extra) extra.call(this, mdef, el, item);
|
||||
|
||||
// apply svg style attributes
|
||||
// note: element may be modified by 'extra' method
|
||||
if (element) this.style(element, item);
|
||||
};
|
||||
|
||||
function emit(name, value, ns) {
|
||||
// early exit if value is unchanged
|
||||
if (value === values[name]) return;
|
||||
|
||||
// use appropriate method given namespace (ns)
|
||||
if (ns) {
|
||||
setAttributeNS(element, name, value, ns);
|
||||
} else {
|
||||
setAttribute(element, name, value);
|
||||
}
|
||||
|
||||
// note current value for future comparison
|
||||
values[name] = value;
|
||||
}
|
||||
|
||||
function setAttribute(el, name, value) {
|
||||
if (value != null) {
|
||||
// if value is provided, update DOM attribute
|
||||
el.setAttribute(name, value);
|
||||
} else {
|
||||
// else remove DOM attribute
|
||||
el.removeAttribute(name);
|
||||
}
|
||||
}
|
||||
|
||||
function setAttributeNS(el, name, value, ns) {
|
||||
if (value != null) {
|
||||
// if value is provided, update DOM attribute
|
||||
el.setAttributeNS(ns, name, value);
|
||||
} else {
|
||||
// else remove DOM attribute
|
||||
el.removeAttributeNS(ns, name);
|
||||
}
|
||||
}
|
||||
|
||||
prototype.style = function(el, o) {
|
||||
if (o == null) return;
|
||||
|
||||
for (const prop in styles) {
|
||||
let value = prop === 'font' ? fontFamily(o) : o[prop];
|
||||
if (value === values[prop]) continue;
|
||||
|
||||
const name = styles[prop];
|
||||
if (value == null) {
|
||||
el.removeAttribute(name);
|
||||
} else {
|
||||
if (isGradient(value)) {
|
||||
value = gradientRef(value, this._defs.gradient, href());
|
||||
}
|
||||
el.setAttribute(name, value + '');
|
||||
}
|
||||
|
||||
values[prop] = value;
|
||||
}
|
||||
};
|
||||
|
||||
function href() {
|
||||
let loc;
|
||||
return typeof window === 'undefined' ? ''
|
||||
: (loc = window.location).hash ? loc.href.slice(0, -loc.hash.length)
|
||||
: loc.href;
|
||||
}
|
||||
365
node_modules/vega-scenegraph/src/SVGStringRenderer.js
generated
vendored
Normal file
365
node_modules/vega-scenegraph/src/SVGStringRenderer.js
generated
vendored
Normal file
@@ -0,0 +1,365 @@
|
||||
import Renderer from './Renderer';
|
||||
import {gradientRef, isGradient, patternPrefix} from './Gradient';
|
||||
import marks from './marks/index';
|
||||
import {ariaItemAttributes, ariaMarkAttributes} from './util/aria';
|
||||
import {cssClass} from './util/dom';
|
||||
import {closeTag, openTag} from './util/tags';
|
||||
import {fontFamily, fontSize, lineHeight, textLines, textValue} from './util/text';
|
||||
import {visit} from './util/visit';
|
||||
import clip from './util/svg/clip';
|
||||
import metadata from './util/svg/metadata';
|
||||
import {rootAttributes, styles} from './util/svg/styles';
|
||||
import {extend, inherits, isArray} from 'vega-util';
|
||||
|
||||
export default function SVGStringRenderer(loader) {
|
||||
Renderer.call(this, loader);
|
||||
|
||||
this._text = {
|
||||
head: '',
|
||||
bg: '',
|
||||
root: '',
|
||||
foot: '',
|
||||
defs: '',
|
||||
body: ''
|
||||
};
|
||||
|
||||
this._defs = {
|
||||
gradient: {},
|
||||
clipping: {}
|
||||
};
|
||||
}
|
||||
|
||||
var prototype = inherits(SVGStringRenderer, Renderer);
|
||||
var base = Renderer.prototype;
|
||||
|
||||
prototype.resize = function(width, height, origin, scaleFactor) {
|
||||
base.resize.call(this, width, height, origin, scaleFactor);
|
||||
var o = this._origin,
|
||||
t = this._text;
|
||||
|
||||
var attr = {
|
||||
class: 'marks',
|
||||
width: this._width * this._scale,
|
||||
height: this._height * this._scale,
|
||||
viewBox: '0 0 ' + this._width + ' ' + this._height
|
||||
};
|
||||
for (var key in metadata) {
|
||||
attr[key] = metadata[key];
|
||||
}
|
||||
|
||||
t.head = openTag('svg', attr);
|
||||
|
||||
var bg = this._bgcolor;
|
||||
if (bg === 'transparent' || bg === 'none') bg = null;
|
||||
|
||||
if (bg) {
|
||||
t.bg = openTag('rect', {
|
||||
width: this._width,
|
||||
height: this._height,
|
||||
fill: bg
|
||||
}) + closeTag('rect');
|
||||
} else {
|
||||
t.bg = '';
|
||||
}
|
||||
|
||||
t.root = openTag('g', extend(
|
||||
{}, rootAttributes, {transform: 'translate(' + o + ')'}
|
||||
));
|
||||
|
||||
t.foot = closeTag('g') + closeTag('svg');
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
prototype.background = function() {
|
||||
var rv = base.background.apply(this, arguments);
|
||||
if (arguments.length && this._text.head) {
|
||||
this.resize(this._width, this._height, this._origin, this._scale);
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
prototype.svg = function() {
|
||||
var t = this._text;
|
||||
return t.head + t.defs + t.bg + t.root + t.body + t.foot;
|
||||
};
|
||||
|
||||
prototype._render = function(scene) {
|
||||
this._text.body = this.mark(scene);
|
||||
this._text.defs = this.buildDefs();
|
||||
return this;
|
||||
};
|
||||
|
||||
prototype.buildDefs = function() {
|
||||
let defs = '', tag;
|
||||
|
||||
for (const id in this._defs.gradient) {
|
||||
const def = this._defs.gradient[id],
|
||||
stops = def.stops;
|
||||
|
||||
if (def.gradient === 'radial') {
|
||||
// SVG radial gradients automatically transform to normalized bbox
|
||||
// coordinates, in a way that is cumbersome to replicate in canvas.
|
||||
// We wrap the radial gradient in a pattern element, allowing us to
|
||||
// maintain a circular gradient that matches what canvas provides.
|
||||
|
||||
defs += openTag(tag = 'pattern', {
|
||||
id: patternPrefix + id,
|
||||
viewBox: '0,0,1,1',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
preserveAspectRatio: 'xMidYMid slice'
|
||||
});
|
||||
|
||||
defs += openTag('rect', {
|
||||
width: '1',
|
||||
height: '1',
|
||||
fill: 'url(#' + id + ')'
|
||||
}) + closeTag('rect');
|
||||
|
||||
defs += closeTag(tag);
|
||||
|
||||
defs += openTag(tag = 'radialGradient', {
|
||||
id: id,
|
||||
fx: def.x1,
|
||||
fy: def.y1,
|
||||
fr: def.r1,
|
||||
cx: def.x2,
|
||||
cy: def.y2,
|
||||
r: def.r2
|
||||
});
|
||||
} else {
|
||||
defs += openTag(tag = 'linearGradient', {
|
||||
id: id,
|
||||
x1: def.x1,
|
||||
x2: def.x2,
|
||||
y1: def.y1,
|
||||
y2: def.y2
|
||||
});
|
||||
}
|
||||
|
||||
for (let i = 0; i < stops.length; ++i) {
|
||||
defs += openTag('stop', {
|
||||
offset: stops[i].offset,
|
||||
'stop-color': stops[i].color
|
||||
}) + closeTag('stop');
|
||||
}
|
||||
|
||||
defs += closeTag(tag);
|
||||
}
|
||||
|
||||
for (const id in this._defs.clipping) {
|
||||
const def = this._defs.clipping[id];
|
||||
|
||||
defs += openTag('clipPath', {id: id});
|
||||
|
||||
if (def.path) {
|
||||
defs += openTag('path', {
|
||||
d: def.path
|
||||
}) + closeTag('path');
|
||||
} else {
|
||||
defs += openTag('rect', {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: def.width,
|
||||
height: def.height
|
||||
}) + closeTag('rect');
|
||||
}
|
||||
|
||||
defs += closeTag('clipPath');
|
||||
}
|
||||
|
||||
return defs ? (openTag('defs') + defs + closeTag('defs')) : '';
|
||||
};
|
||||
|
||||
prototype.attr = function(scene, item, attrs, tag) {
|
||||
const object = {},
|
||||
emit = (name, value, ns, prefixed) => {
|
||||
object[prefixed || name] = value;
|
||||
};
|
||||
|
||||
// apply mark specific attributes
|
||||
if (Array.isArray(attrs)) {
|
||||
attrs.forEach(fn => fn(emit, item, this));
|
||||
} else {
|
||||
attrs(emit, item, this);
|
||||
}
|
||||
|
||||
// apply style attributes
|
||||
if (tag) {
|
||||
applyStyles(object, item, scene, tag, this._defs);
|
||||
}
|
||||
|
||||
return object;
|
||||
};
|
||||
|
||||
prototype.href = function(item) {
|
||||
var that = this,
|
||||
href = item.href,
|
||||
attr;
|
||||
|
||||
if (href) {
|
||||
if (attr = that._hrefs && that._hrefs[href]) {
|
||||
return attr;
|
||||
} else {
|
||||
that.sanitizeURL(href).then(attr => {
|
||||
// rewrite to use xlink namespace
|
||||
// note that this will be deprecated in SVG 2.0
|
||||
attr['xlink:href'] = attr.href;
|
||||
attr.href = null;
|
||||
(that._hrefs || (that._hrefs = {}))[href] = attr;
|
||||
});
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
prototype.mark = function(scene) {
|
||||
const mdef = marks[scene.marktype],
|
||||
tag = mdef.tag,
|
||||
attrList = [ariaItemAttributes, mdef.attr];
|
||||
|
||||
let str = '';
|
||||
|
||||
// render opening group tag
|
||||
str += openTag('g', extend(
|
||||
{
|
||||
'class': cssClass(scene),
|
||||
'clip-path': scene.clip ? clip(this, scene, scene.group) : null
|
||||
},
|
||||
ariaMarkAttributes(scene),
|
||||
{
|
||||
'pointer-events': tag !== 'g' && scene.interactive === false ? 'none' : null
|
||||
}
|
||||
));
|
||||
|
||||
// render contained elements
|
||||
const process = item => {
|
||||
const href = this.href(item);
|
||||
if (href) str += openTag('a', href);
|
||||
|
||||
str += openTag(
|
||||
tag,
|
||||
this.attr(scene, item, attrList, tag !== 'g' ? tag : null)
|
||||
);
|
||||
|
||||
if (tag === 'text') {
|
||||
const tl = textLines(item);
|
||||
if (isArray(tl)) {
|
||||
// multi-line text
|
||||
const attrs = {x: 0, dy: lineHeight(item)};
|
||||
for (let i=0; i<tl.length; ++i) {
|
||||
str += openTag('tspan', i ? attrs: null)
|
||||
+ escape_text(textValue(item, tl[i]))
|
||||
+ closeTag('tspan');
|
||||
}
|
||||
} else {
|
||||
// single-line text
|
||||
str += escape_text(textValue(item, tl));
|
||||
}
|
||||
} else if (tag === 'g') {
|
||||
const fore = item.strokeForeground,
|
||||
fill = item.fill,
|
||||
stroke = item.stroke;
|
||||
|
||||
if (fore && stroke) {
|
||||
item.stroke = null;
|
||||
}
|
||||
|
||||
str += openTag(
|
||||
'path',
|
||||
this.attr(scene, item, mdef.background, 'bgrect')
|
||||
) + closeTag('path');
|
||||
|
||||
str += openTag('g', this.attr(scene, item, mdef.content))
|
||||
+ this.markGroup(item)
|
||||
+ closeTag('g');
|
||||
|
||||
if (fore && stroke) {
|
||||
if (fill) item.fill = null;
|
||||
item.stroke = stroke;
|
||||
|
||||
str += openTag(
|
||||
'path',
|
||||
this.attr(scene, item, mdef.foreground, 'bgrect')
|
||||
) + closeTag('path');
|
||||
|
||||
if (fill) item.fill = fill;
|
||||
} else {
|
||||
str += openTag(
|
||||
'path',
|
||||
this.attr(scene, item, mdef.foreground, 'bgfore')
|
||||
) + closeTag('path');
|
||||
}
|
||||
}
|
||||
|
||||
str += closeTag(tag);
|
||||
if (href) str += closeTag('a');
|
||||
};
|
||||
|
||||
if (mdef.nested) {
|
||||
if (scene.items && scene.items.length) process(scene.items[0]);
|
||||
} else {
|
||||
visit(scene, process);
|
||||
}
|
||||
|
||||
// render closing group tag
|
||||
return str + closeTag('g');
|
||||
};
|
||||
|
||||
prototype.markGroup = function(scene) {
|
||||
let str = '';
|
||||
visit(scene, item => { str += this.mark(item); });
|
||||
return str;
|
||||
};
|
||||
|
||||
function applyStyles(s, item, scene, tag, defs) {
|
||||
if (item == null) return s;
|
||||
|
||||
if (tag === 'bgrect' && scene.interactive === false) {
|
||||
s['pointer-events'] = 'none';
|
||||
}
|
||||
|
||||
if (tag === 'bgfore') {
|
||||
if (scene.interactive === false) {
|
||||
s['pointer-events'] = 'none';
|
||||
}
|
||||
s.display = 'none';
|
||||
if (item.fill !== null) return s;
|
||||
}
|
||||
|
||||
if (tag === 'image' && item.smooth === false) {
|
||||
s.style = 'image-rendering: optimizeSpeed; image-rendering: pixelated;';
|
||||
}
|
||||
|
||||
if (tag === 'text') {
|
||||
s['font-family'] = fontFamily(item);
|
||||
s['font-size'] = fontSize(item) + 'px';
|
||||
if (item.fontStyle) s['font-style'] = item.fontStyle;
|
||||
if (item.fontVariant) s['font-variant'] = item.fontVariant;
|
||||
if (item.fontWeight) s['font-weight'] = item.fontWeight;
|
||||
}
|
||||
|
||||
for (const prop in styles) {
|
||||
let value = item[prop];
|
||||
const name = styles[prop];
|
||||
|
||||
if (value === 'transparent' && (name === 'fill' || name === 'stroke')) {
|
||||
// transparent is not a legal SVG value
|
||||
// we can skip it to rely on default 'none' instead
|
||||
} else if (value != null) {
|
||||
if (isGradient(value)) {
|
||||
value = gradientRef(value, defs.gradient, '');
|
||||
}
|
||||
s[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
function escape_text(s) {
|
||||
return s.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
}
|
||||
54
node_modules/vega-scenegraph/src/Scenegraph.js
generated
vendored
Normal file
54
node_modules/vega-scenegraph/src/Scenegraph.js
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
import Bounds from './Bounds';
|
||||
import GroupItem from './GroupItem';
|
||||
import {sceneFromJSON, sceneToJSON} from './util/serialize';
|
||||
|
||||
export default function Scenegraph(scene) {
|
||||
if (arguments.length) {
|
||||
this.root = sceneFromJSON(scene);
|
||||
} else {
|
||||
this.root = createMark({
|
||||
marktype: 'group',
|
||||
name: 'root',
|
||||
role: 'frame'
|
||||
});
|
||||
this.root.items = [new GroupItem(this.root)];
|
||||
}
|
||||
}
|
||||
|
||||
var prototype = Scenegraph.prototype;
|
||||
|
||||
prototype.toJSON = function(indent) {
|
||||
return sceneToJSON(this.root, indent || 0);
|
||||
};
|
||||
|
||||
prototype.mark = function(markdef, group, index) {
|
||||
group = group || this.root.items[0];
|
||||
var mark = createMark(markdef, group);
|
||||
group.items[index] = mark;
|
||||
if (mark.zindex) mark.group.zdirty = true;
|
||||
return mark;
|
||||
};
|
||||
|
||||
function createMark(def, group) {
|
||||
const mark = {
|
||||
bounds: new Bounds(),
|
||||
clip: !!def.clip,
|
||||
group: group,
|
||||
interactive: def.interactive === false ? false : true,
|
||||
items: [],
|
||||
marktype: def.marktype,
|
||||
name: def.name || undefined,
|
||||
role: def.role || undefined,
|
||||
zindex: def.zindex || 0
|
||||
};
|
||||
|
||||
// add accessibility properties if defined
|
||||
if (def.aria != null) {
|
||||
mark.aria = def.aria;
|
||||
}
|
||||
if (def.description) {
|
||||
mark.description = def.description;
|
||||
}
|
||||
|
||||
return mark;
|
||||
}
|
||||
17
node_modules/vega-scenegraph/src/bound/boundClip.js
generated
vendored
Normal file
17
node_modules/vega-scenegraph/src/bound/boundClip.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import Bounds from '../Bounds';
|
||||
import boundContext from './boundContext';
|
||||
import {isFunction} from 'vega-util';
|
||||
|
||||
var clipBounds = new Bounds();
|
||||
|
||||
export default function(mark) {
|
||||
var clip = mark.clip;
|
||||
|
||||
if (isFunction(clip)) {
|
||||
clip(boundContext(clipBounds.clear()));
|
||||
} else if (clip) {
|
||||
clipBounds.set(0, 0, mark.group.width, mark.group.height);
|
||||
} else return;
|
||||
|
||||
mark.bounds.intersect(clipBounds);
|
||||
}
|
||||
119
node_modules/vega-scenegraph/src/bound/boundContext.js
generated
vendored
Normal file
119
node_modules/vega-scenegraph/src/bound/boundContext.js
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
import {Epsilon, HalfPi, Tau} from '../util/constants';
|
||||
|
||||
var bounds, lx, ly,
|
||||
circleThreshold = Tau - 1e-8;
|
||||
|
||||
export default function context(_) {
|
||||
bounds = _;
|
||||
return context;
|
||||
}
|
||||
|
||||
function noop() {}
|
||||
|
||||
function add(x, y) { bounds.add(x, y); }
|
||||
|
||||
function addL(x, y) { add(lx = x, ly = y); }
|
||||
|
||||
function addX(x) { add(x, bounds.y1); }
|
||||
|
||||
function addY(y) { add(bounds.x1, y); }
|
||||
|
||||
context.beginPath = noop;
|
||||
|
||||
context.closePath = noop;
|
||||
|
||||
context.moveTo = addL;
|
||||
|
||||
context.lineTo = addL;
|
||||
|
||||
context.rect = function(x, y, w, h) {
|
||||
add(x + w, y + h);
|
||||
addL(x, y);
|
||||
};
|
||||
|
||||
context.quadraticCurveTo = function(x1, y1, x2, y2) {
|
||||
quadExtrema(lx, x1, x2, addX);
|
||||
quadExtrema(ly, y1, y2, addY);
|
||||
addL(x2, y2);
|
||||
};
|
||||
|
||||
function quadExtrema(x0, x1, x2, cb) {
|
||||
const t = (x0 - x1) / (x0 + x2 - 2 * x1);
|
||||
if (0 < t && t < 1) cb(x0 + (x1 - x0) * t);
|
||||
}
|
||||
|
||||
context.bezierCurveTo = function(x1, y1, x2, y2, x3, y3) {
|
||||
cubicExtrema(lx, x1, x2, x3, addX);
|
||||
cubicExtrema(ly, y1, y2, y3, addY);
|
||||
addL(x3, y3);
|
||||
};
|
||||
|
||||
function cubicExtrema(x0, x1, x2, x3, cb) {
|
||||
const a = x3 - x0 + 3 * x1 - 3 * x2,
|
||||
b = x0 + x2 - 2 * x1,
|
||||
c = x0 - x1;
|
||||
|
||||
let t0 = 0, t1 = 0, r;
|
||||
|
||||
// solve for parameter t
|
||||
if (Math.abs(a) > Epsilon) {
|
||||
// quadratic equation
|
||||
r = b * b + c * a;
|
||||
if (r >= 0) {
|
||||
r = Math.sqrt(r);
|
||||
t0 = (-b + r) / a;
|
||||
t1 = (-b - r) / a;
|
||||
}
|
||||
} else {
|
||||
// linear equation
|
||||
t0 = 0.5 * c / b;
|
||||
}
|
||||
|
||||
// calculate position
|
||||
if (0 < t0 && t0 < 1) cb(cubic(t0, x0, x1, x2, x3));
|
||||
if (0 < t1 && t1 < 1) cb(cubic(t1, x0, x1, x2, x3));
|
||||
}
|
||||
|
||||
function cubic(t, x0, x1, x2, x3) {
|
||||
const s = 1 - t, s2 = s * s, t2 = t * t;
|
||||
return (s2 * s * x0) + (3 * s2 * t * x1) + (3 * s * t2 * x2) + (t2 * t * x3);
|
||||
}
|
||||
|
||||
context.arc = function(cx, cy, r, sa, ea, ccw) {
|
||||
// store last point on path
|
||||
lx = r * Math.cos(ea) + cx;
|
||||
ly = r * Math.sin(ea) + cy;
|
||||
|
||||
if (Math.abs(ea - sa) > circleThreshold) {
|
||||
// treat as full circle
|
||||
add(cx - r, cy - r);
|
||||
add(cx + r, cy + r);
|
||||
} else {
|
||||
const update = a => add(r * Math.cos(a) + cx, r * Math.sin(a) + cy);
|
||||
let s, i;
|
||||
|
||||
// sample end points
|
||||
update(sa);
|
||||
update(ea);
|
||||
|
||||
// sample interior points aligned with 90 degrees
|
||||
if (ea !== sa) {
|
||||
sa = sa % Tau; if (sa < 0) sa += Tau;
|
||||
ea = ea % Tau; if (ea < 0) ea += Tau;
|
||||
|
||||
if (ea < sa) {
|
||||
ccw = !ccw; // flip direction
|
||||
s = sa; sa = ea; ea = s; // swap end-points
|
||||
}
|
||||
|
||||
if (ccw) {
|
||||
ea -= Tau;
|
||||
s = sa - (sa % HalfPi);
|
||||
for (i=0; i<4 && s>ea; ++i, s-=HalfPi) update(s);
|
||||
} else {
|
||||
s = sa - (sa % HalfPi) + HalfPi;
|
||||
for (i=0; i<4 && s<ea; ++i, s=s+HalfPi) update(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
10
node_modules/vega-scenegraph/src/bound/boundItem.js
generated
vendored
Normal file
10
node_modules/vega-scenegraph/src/bound/boundItem.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import Bounds from '../Bounds';
|
||||
import marks from '../marks/index';
|
||||
|
||||
export default function(item, func, opt) {
|
||||
var type = marks[item.mark.marktype],
|
||||
bound = func || type.bound;
|
||||
if (type.nested) item = item.mark;
|
||||
|
||||
return bound(item.bounds || (item.bounds = new Bounds()), item, opt);
|
||||
}
|
||||
38
node_modules/vega-scenegraph/src/bound/boundMark.js
generated
vendored
Normal file
38
node_modules/vega-scenegraph/src/bound/boundMark.js
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
import Bounds from '../Bounds';
|
||||
import boundItem from './boundItem';
|
||||
import marks from '../marks/index';
|
||||
|
||||
var DUMMY = {mark: null};
|
||||
|
||||
export default function(mark, bounds, opt) {
|
||||
var type = marks[mark.marktype],
|
||||
bound = type.bound,
|
||||
items = mark.items,
|
||||
hasItems = items && items.length,
|
||||
i, n, item, b;
|
||||
|
||||
if (type.nested) {
|
||||
if (hasItems) {
|
||||
item = items[0];
|
||||
} else {
|
||||
// no items, fake it
|
||||
DUMMY.mark = mark;
|
||||
item = DUMMY;
|
||||
}
|
||||
b = boundItem(item, bound, opt);
|
||||
bounds = bounds && bounds.union(b) || b;
|
||||
return bounds;
|
||||
}
|
||||
|
||||
bounds = bounds
|
||||
|| mark.bounds && mark.bounds.clear()
|
||||
|| new Bounds();
|
||||
|
||||
if (hasItems) {
|
||||
for (i=0, n=items.length; i<n; ++i) {
|
||||
bounds.union(boundItem(items[i], bound, opt));
|
||||
}
|
||||
}
|
||||
|
||||
return mark.bounds = bounds;
|
||||
}
|
||||
12
node_modules/vega-scenegraph/src/bound/boundStroke.js
generated
vendored
Normal file
12
node_modules/vega-scenegraph/src/bound/boundStroke.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
export default function(bounds, item, miter) {
|
||||
if (item.stroke && item.opacity !== 0 && item.strokeOpacity !== 0) {
|
||||
const sw = item.strokeWidth != null ? +item.strokeWidth : 1;
|
||||
bounds.expand(sw + (miter ? miterAdjustment(item, sw) : 0));
|
||||
}
|
||||
return bounds;
|
||||
}
|
||||
|
||||
function miterAdjustment(item, strokeWidth) {
|
||||
// TODO: more sophisticated adjustment? Or miter support in boundContext?
|
||||
return item.strokeJoin && item.strokeJoin !== 'miter' ? 0 : strokeWidth;
|
||||
}
|
||||
78
node_modules/vega-scenegraph/src/intersect.js
generated
vendored
Normal file
78
node_modules/vega-scenegraph/src/intersect.js
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
import Marks from './marks/index';
|
||||
import {error} from 'vega-util';
|
||||
import Bounds from './Bounds';
|
||||
|
||||
export function intersect(scene, bounds, filter) {
|
||||
const hits = [], // intersection results
|
||||
box = new Bounds().union(bounds), // defensive copy
|
||||
type = scene.marktype;
|
||||
|
||||
return type ? intersectMark(scene, box, filter, hits)
|
||||
: type === 'group' ? intersectGroup(scene, box, filter, hits)
|
||||
: error('Intersect scene must be mark node or group item.');
|
||||
}
|
||||
|
||||
function intersectMark(mark, box, filter, hits) {
|
||||
if (visitMark(mark, box, filter)) {
|
||||
const items = mark.items,
|
||||
type = mark.marktype,
|
||||
n = items.length;
|
||||
|
||||
let i = 0;
|
||||
|
||||
if (type === 'group') {
|
||||
for (; i<n; ++i) {
|
||||
intersectGroup(items[i], box, filter, hits);
|
||||
}
|
||||
} else {
|
||||
for (const test = Marks[type].isect; i<n; ++i) {
|
||||
let item = items[i];
|
||||
if (intersectItem(item, box, test)) hits.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return hits;
|
||||
}
|
||||
|
||||
function visitMark(mark, box, filter) {
|
||||
// process if bounds intersect and if
|
||||
// (1) mark is a group mark (so we must recurse), or
|
||||
// (2) mark is interactive and passes filter
|
||||
return mark.bounds && box.intersects(mark.bounds) && (
|
||||
mark.marktype === 'group' ||
|
||||
mark.interactive !== false && (!filter || filter(mark))
|
||||
);
|
||||
}
|
||||
|
||||
function intersectGroup(group, box, filter, hits) {
|
||||
// test intersect against group
|
||||
// skip groups by default unless filter says otherwise
|
||||
if ((filter && filter(group.mark)) &&
|
||||
intersectItem(group, box, Marks.group.isect)) {
|
||||
hits.push(group);
|
||||
}
|
||||
|
||||
// recursively test children marks
|
||||
// translate box to group coordinate space
|
||||
const marks = group.items,
|
||||
n = marks && marks.length;
|
||||
|
||||
if (n) {
|
||||
const x = group.x || 0,
|
||||
y = group.y || 0;
|
||||
box.translate(-x, -y);
|
||||
for (let i=0; i<n; ++i) {
|
||||
intersectMark(marks[i], box, filter, hits);
|
||||
}
|
||||
box.translate(x, y);
|
||||
}
|
||||
|
||||
return hits;
|
||||
}
|
||||
|
||||
function intersectItem(item, box, test) {
|
||||
// test bounds enclosure, bounds intersection, then detailed test
|
||||
const bounds = item.bounds;
|
||||
return box.encloses(bounds) || (box.intersects(bounds) && test(item, box));
|
||||
}
|
||||
|
||||
4
node_modules/vega-scenegraph/src/marks/arc.js
generated
vendored
Normal file
4
node_modules/vega-scenegraph/src/marks/arc.js
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import {arc} from '../path/shapes';
|
||||
import markItemPath from './markItemPath';
|
||||
|
||||
export default markItemPath('arc', arc);
|
||||
5
node_modules/vega-scenegraph/src/marks/area.js
generated
vendored
Normal file
5
node_modules/vega-scenegraph/src/marks/area.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import {area} from '../path/shapes';
|
||||
import {pickArea} from '../util/pickPath';
|
||||
import markMultiItemPath from './markMultiItemPath';
|
||||
|
||||
export default markMultiItemPath('area', area, pickArea);
|
||||
202
node_modules/vega-scenegraph/src/marks/group.js
generated
vendored
Normal file
202
node_modules/vega-scenegraph/src/marks/group.js
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
import {hasCornerRadius, rectangle} from '../path/shapes';
|
||||
import boundStroke from '../bound/boundStroke';
|
||||
import {intersectRect} from '../util/intersect';
|
||||
import value from '../util/value';
|
||||
import {pickVisit, visit} from '../util/visit';
|
||||
import blend from '../util/canvas/blend';
|
||||
import {clipGroup} from '../util/canvas/clip';
|
||||
import fill from '../util/canvas/fill';
|
||||
import stroke from '../util/canvas/stroke';
|
||||
import {hitPath} from '../util/canvas/pick';
|
||||
import clip from '../util/svg/clip';
|
||||
import {translateItem} from '../util/svg/transform';
|
||||
|
||||
function offset(item) {
|
||||
const sw = value(item.strokeWidth, 1);
|
||||
return item.strokeOffset != null ? item.strokeOffset
|
||||
: item.stroke && sw > 0.5 && sw < 1.5 ? 0.5 - Math.abs(sw - 1)
|
||||
: 0;
|
||||
}
|
||||
|
||||
function attr(emit, item) {
|
||||
emit('transform', translateItem(item));
|
||||
}
|
||||
|
||||
function emitRectangle(emit, item) {
|
||||
const off = offset(item);
|
||||
emit('d', rectangle(null, item, off, off));
|
||||
}
|
||||
|
||||
function background(emit, item) {
|
||||
emit('class', 'background');
|
||||
emit('aria-hidden', true);
|
||||
emitRectangle(emit, item);
|
||||
}
|
||||
|
||||
function foreground(emit, item) {
|
||||
emit('class', 'foreground');
|
||||
emit('aria-hidden', true);
|
||||
if (item.strokeForeground) {
|
||||
emitRectangle(emit, item);
|
||||
} else {
|
||||
emit('d', '');
|
||||
}
|
||||
}
|
||||
|
||||
function content(emit, item, renderer) {
|
||||
const url = item.clip ? clip(renderer, item, item) : null;
|
||||
emit('clip-path', url);
|
||||
}
|
||||
|
||||
function bound(bounds, group) {
|
||||
if (!group.clip && group.items) {
|
||||
const items = group.items, m = items.length;
|
||||
for (let j=0; j<m; ++j) {
|
||||
bounds.union(items[j].bounds);
|
||||
}
|
||||
}
|
||||
|
||||
if ((group.clip || group.width || group.height) && !group.noBound) {
|
||||
bounds.add(0, 0).add(group.width || 0, group.height || 0);
|
||||
}
|
||||
|
||||
boundStroke(bounds, group);
|
||||
|
||||
return bounds.translate(group.x || 0, group.y || 0);
|
||||
}
|
||||
|
||||
function rectanglePath(context, group, x, y) {
|
||||
const off = offset(group);
|
||||
context.beginPath();
|
||||
rectangle(context, group, (x || 0) + off, (y || 0) + off);
|
||||
}
|
||||
|
||||
const hitBackground = hitPath(rectanglePath);
|
||||
const hitForeground = hitPath(rectanglePath, false);
|
||||
|
||||
function draw(context, scene, bounds) {
|
||||
visit(scene, group => {
|
||||
const gx = group.x || 0,
|
||||
gy = group.y || 0,
|
||||
fore = group.strokeForeground,
|
||||
opacity = group.opacity == null ? 1 : group.opacity;
|
||||
|
||||
// draw group background
|
||||
if ((group.stroke || group.fill) && opacity) {
|
||||
rectanglePath(context, group, gx, gy);
|
||||
blend(context, group);
|
||||
if (group.fill && fill(context, group, opacity)) {
|
||||
context.fill();
|
||||
}
|
||||
if (group.stroke && !fore && stroke(context, group, opacity)) {
|
||||
context.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
// setup graphics context, set clip and bounds
|
||||
context.save();
|
||||
context.translate(gx, gy);
|
||||
if (group.clip) clipGroup(context, group);
|
||||
if (bounds) bounds.translate(-gx, -gy);
|
||||
|
||||
// draw group contents
|
||||
visit(group, item => {
|
||||
this.draw(context, item, bounds);
|
||||
});
|
||||
|
||||
// restore graphics context
|
||||
if (bounds) bounds.translate(gx, gy);
|
||||
context.restore();
|
||||
|
||||
// draw group foreground
|
||||
if (fore && group.stroke && opacity) {
|
||||
rectanglePath(context, group, gx, gy);
|
||||
blend(context, group);
|
||||
if (stroke(context, group, opacity)) {
|
||||
context.stroke();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function pick(context, scene, x, y, gx, gy) {
|
||||
if (scene.bounds && !scene.bounds.contains(gx, gy) || !scene.items) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const cx = x * context.pixelRatio,
|
||||
cy = y * context.pixelRatio;
|
||||
|
||||
return pickVisit(scene, group => {
|
||||
let hit, fore, ix, dx, dy, dw, dh, b, c;
|
||||
|
||||
// first hit test bounding box
|
||||
b = group.bounds;
|
||||
if (b && !b.contains(gx, gy)) return;
|
||||
|
||||
// passed bounds check, test rectangular clip
|
||||
dx = group.x || 0;
|
||||
dy = group.y || 0;
|
||||
dw = dx + (group.width || 0);
|
||||
dh = dy + (group.height || 0);
|
||||
c = group.clip;
|
||||
if (c && (gx < dx || gx > dw || gy < dy || gy > dh)) return;
|
||||
|
||||
// adjust coordinate system
|
||||
context.save();
|
||||
context.translate(dx, dy);
|
||||
dx = gx - dx;
|
||||
dy = gy - dy;
|
||||
|
||||
// test background for rounded corner clip
|
||||
if (c && hasCornerRadius(group) && !hitBackground(context, group, cx, cy)) {
|
||||
context.restore();
|
||||
return null;
|
||||
}
|
||||
|
||||
fore = group.strokeForeground;
|
||||
ix = scene.interactive !== false;
|
||||
|
||||
// hit test against group foreground
|
||||
if (ix && fore && group.stroke
|
||||
&& hitForeground(context, group, cx, cy)) {
|
||||
context.restore();
|
||||
return group;
|
||||
}
|
||||
|
||||
// hit test against contained marks
|
||||
hit = pickVisit(group, mark => pickMark(mark, dx, dy)
|
||||
? this.pick(mark, x, y, dx, dy)
|
||||
: null
|
||||
);
|
||||
|
||||
// hit test against group background
|
||||
if (!hit && ix && (group.fill || (!fore && group.stroke))
|
||||
&& hitBackground(context, group, cx, cy)) {
|
||||
hit = group;
|
||||
}
|
||||
|
||||
// restore state and return
|
||||
context.restore();
|
||||
return hit || null;
|
||||
});
|
||||
}
|
||||
|
||||
function pickMark(mark, x, y) {
|
||||
return (mark.interactive !== false || mark.marktype === 'group')
|
||||
&& mark.bounds && mark.bounds.contains(x, y);
|
||||
}
|
||||
|
||||
export default {
|
||||
type: 'group',
|
||||
tag: 'g',
|
||||
nested: false,
|
||||
attr: attr,
|
||||
bound: bound,
|
||||
draw: draw,
|
||||
pick: pick,
|
||||
isect: intersectRect,
|
||||
content: content,
|
||||
background: background,
|
||||
foreground: foreground
|
||||
};
|
||||
115
node_modules/vega-scenegraph/src/marks/image.js
generated
vendored
Normal file
115
node_modules/vega-scenegraph/src/marks/image.js
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
import {visit} from '../util/visit';
|
||||
import blend from '../util/canvas/blend';
|
||||
import {pick} from '../util/canvas/pick';
|
||||
import metadata from '../util/svg/metadata';
|
||||
import {translate} from '../util/svg/transform';
|
||||
import {truthy} from 'vega-util';
|
||||
|
||||
function getImage(item, renderer) {
|
||||
var image = item.image;
|
||||
if (!image || item.url && item.url !== image.url) {
|
||||
image = {complete: false, width: 0, height: 0};
|
||||
renderer.loadImage(item.url).then(image => {
|
||||
item.image = image;
|
||||
item.image.url = item.url;
|
||||
});
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
function imageWidth(item, image) {
|
||||
return item.width != null ? item.width
|
||||
: !image || !image.width ? 0
|
||||
: item.aspect !== false && item.height ? item.height * image.width / image.height
|
||||
: image.width;
|
||||
}
|
||||
|
||||
function imageHeight(item, image) {
|
||||
return item.height != null ? item.height
|
||||
: !image || !image.height ? 0
|
||||
: item.aspect !== false && item.width ? item.width * image.height / image.width
|
||||
: image.height;
|
||||
}
|
||||
|
||||
function imageXOffset(align, w) {
|
||||
return align === 'center' ? w / 2 : align === 'right' ? w : 0;
|
||||
}
|
||||
|
||||
function imageYOffset(baseline, h) {
|
||||
return baseline === 'middle' ? h / 2 : baseline === 'bottom' ? h : 0;
|
||||
}
|
||||
|
||||
function attr(emit, item, renderer) {
|
||||
const img = getImage(item, renderer),
|
||||
w = imageWidth(item, img),
|
||||
h = imageHeight(item, img),
|
||||
x = (item.x || 0) - imageXOffset(item.align, w),
|
||||
y = (item.y || 0) - imageYOffset(item.baseline, h),
|
||||
i = !img.src && img.toDataURL ? img.toDataURL() : img.src || '';
|
||||
|
||||
emit('href', i, metadata['xmlns:xlink'], 'xlink:href');
|
||||
emit('transform', translate(x, y));
|
||||
emit('width', w);
|
||||
emit('height', h);
|
||||
emit('preserveAspectRatio', item.aspect === false ? 'none' : 'xMidYMid');
|
||||
}
|
||||
|
||||
function bound(bounds, item) {
|
||||
const img = item.image,
|
||||
w = imageWidth(item, img),
|
||||
h = imageHeight(item, img),
|
||||
x = (item.x || 0) - imageXOffset(item.align, w),
|
||||
y = (item.y || 0) - imageYOffset(item.baseline, h);
|
||||
|
||||
return bounds.set(x, y, x + w, y + h);
|
||||
}
|
||||
|
||||
function draw(context, scene, bounds) {
|
||||
visit(scene, item => {
|
||||
if (bounds && !bounds.intersects(item.bounds)) return; // bounds check
|
||||
|
||||
let img = getImage(item, this),
|
||||
w = imageWidth(item, img),
|
||||
h = imageHeight(item, img),
|
||||
x = (item.x || 0) - imageXOffset(item.align, w),
|
||||
y = (item.y || 0) - imageYOffset(item.baseline, h),
|
||||
opacity, ar0, ar1, t;
|
||||
|
||||
if (item.aspect !== false) {
|
||||
ar0 = img.width / img.height;
|
||||
ar1 = item.width / item.height;
|
||||
if (ar0 === ar0 && ar1 === ar1 && ar0 !== ar1) {
|
||||
if (ar1 < ar0) {
|
||||
t = w / ar0;
|
||||
y += (h - t) / 2;
|
||||
h = t;
|
||||
} else {
|
||||
t = h * ar0;
|
||||
x += (w - t) / 2;
|
||||
w = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (img.complete || img.toDataURL) {
|
||||
blend(context, item);
|
||||
context.globalAlpha = (opacity = item.opacity) != null ? opacity : 1;
|
||||
context.imageSmoothingEnabled = item.smooth !== false;
|
||||
context.drawImage(img, x, y, w, h);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
type: 'image',
|
||||
tag: 'image',
|
||||
nested: false,
|
||||
attr: attr,
|
||||
bound: bound,
|
||||
draw: draw,
|
||||
pick: pick(),
|
||||
isect: truthy, // bounds check is sufficient
|
||||
get: getImage,
|
||||
xOffset: imageXOffset,
|
||||
yOffset: imageYOffset
|
||||
};
|
||||
27
node_modules/vega-scenegraph/src/marks/index.js
generated
vendored
Normal file
27
node_modules/vega-scenegraph/src/marks/index.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
import arc from './arc';
|
||||
import area from './area';
|
||||
import group from './group';
|
||||
import image from './image';
|
||||
import line from './line';
|
||||
import path from './path';
|
||||
import rect from './rect';
|
||||
import rule from './rule';
|
||||
import shape from './shape';
|
||||
import symbol from './symbol';
|
||||
import text from './text';
|
||||
import trail from './trail';
|
||||
|
||||
export default {
|
||||
arc: arc,
|
||||
area: area,
|
||||
group: group,
|
||||
image: image,
|
||||
line: line,
|
||||
path: path,
|
||||
rect: rect,
|
||||
rule: rule,
|
||||
shape: shape,
|
||||
symbol: symbol,
|
||||
text: text,
|
||||
trail: trail
|
||||
};
|
||||
5
node_modules/vega-scenegraph/src/marks/line.js
generated
vendored
Normal file
5
node_modules/vega-scenegraph/src/marks/line.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import {line} from '../path/shapes';
|
||||
import {pickLine} from '../util/pickPath';
|
||||
import markMultiItemPath from './markMultiItemPath';
|
||||
|
||||
export default markMultiItemPath('line', line, pickLine);
|
||||
53
node_modules/vega-scenegraph/src/marks/markItemPath.js
generated
vendored
Normal file
53
node_modules/vega-scenegraph/src/marks/markItemPath.js
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
import boundStroke from '../bound/boundStroke';
|
||||
import context from '../bound/boundContext';
|
||||
import {intersectPath} from '../util/intersect';
|
||||
import {drawAll} from '../util/canvas/draw';
|
||||
import {pickPath} from '../util/canvas/pick';
|
||||
import {transformItem} from '../util/svg/transform';
|
||||
import {DegToRad} from '../util/constants';
|
||||
|
||||
export default function(type, shape, isect) {
|
||||
|
||||
function attr(emit, item) {
|
||||
emit('transform', transformItem(item));
|
||||
emit('d', shape(null, item));
|
||||
}
|
||||
|
||||
function bound(bounds, item) {
|
||||
var x = item.x || 0,
|
||||
y = item.y || 0;
|
||||
|
||||
shape(context(bounds), item);
|
||||
boundStroke(bounds, item).translate(x, y);
|
||||
if (item.angle) {
|
||||
bounds.rotate(item.angle * DegToRad, x, y);
|
||||
}
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
function draw(context, item) {
|
||||
var x = item.x || 0,
|
||||
y = item.y || 0,
|
||||
a = item.angle || 0;
|
||||
|
||||
context.translate(x, y);
|
||||
if (a) context.rotate(a *= DegToRad);
|
||||
context.beginPath();
|
||||
shape(context, item);
|
||||
if (a) context.rotate(-a);
|
||||
context.translate(-x, -y);
|
||||
}
|
||||
|
||||
return {
|
||||
type: type,
|
||||
tag: 'path',
|
||||
nested: false,
|
||||
attr: attr,
|
||||
bound: bound,
|
||||
draw: drawAll(draw),
|
||||
pick: pickPath(draw),
|
||||
isect: isect || intersectPath(draw)
|
||||
};
|
||||
|
||||
}
|
||||
58
node_modules/vega-scenegraph/src/marks/markMultiItemPath.js
generated
vendored
Normal file
58
node_modules/vega-scenegraph/src/marks/markMultiItemPath.js
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
import boundStroke from '../bound/boundStroke';
|
||||
import context from '../bound/boundContext';
|
||||
import {intersectPoint} from '../util/intersect';
|
||||
import {drawOne} from '../util/canvas/draw';
|
||||
import {hitPath} from '../util/canvas/pick';
|
||||
|
||||
export default function(type, shape, tip) {
|
||||
|
||||
function attr(emit, item) {
|
||||
var items = item.mark.items;
|
||||
if (items.length) emit('d', shape(null, items));
|
||||
}
|
||||
|
||||
function bound(bounds, mark) {
|
||||
var items = mark.items;
|
||||
if (items.length === 0) {
|
||||
return bounds;
|
||||
} else {
|
||||
shape(context(bounds), items);
|
||||
return boundStroke(bounds, items[0]);
|
||||
}
|
||||
}
|
||||
|
||||
function draw(context, items) {
|
||||
context.beginPath();
|
||||
shape(context, items);
|
||||
}
|
||||
|
||||
var hit = hitPath(draw);
|
||||
|
||||
function pick(context, scene, x, y, gx, gy) {
|
||||
var items = scene.items,
|
||||
b = scene.bounds;
|
||||
|
||||
if (!items || !items.length || b && !b.contains(gx, gy)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
x *= context.pixelRatio;
|
||||
y *= context.pixelRatio;
|
||||
return hit(context, items, x, y) ? items[0] : null;
|
||||
}
|
||||
|
||||
return {
|
||||
type: type,
|
||||
tag: 'path',
|
||||
nested: true,
|
||||
attr: attr,
|
||||
bound: bound,
|
||||
draw: drawOne(draw),
|
||||
pick: pick,
|
||||
isect: intersectPoint,
|
||||
tip: tip
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
68
node_modules/vega-scenegraph/src/marks/path.js
generated
vendored
Normal file
68
node_modules/vega-scenegraph/src/marks/path.js
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
import boundStroke from '../bound/boundStroke';
|
||||
import context from '../bound/boundContext';
|
||||
import pathParse from '../path/parse';
|
||||
import pathRender from '../path/render';
|
||||
import {intersectPath} from '../util/intersect';
|
||||
import {drawAll} from '../util/canvas/draw';
|
||||
import {pickPath} from '../util/canvas/pick';
|
||||
import {transformItem} from '../util/svg/transform';
|
||||
import {DegToRad} from '../util/constants';
|
||||
|
||||
function attr(emit, item) {
|
||||
var sx = item.scaleX || 1,
|
||||
sy = item.scaleY || 1;
|
||||
if (sx !== 1 || sy !== 1) {
|
||||
emit('vector-effect', 'non-scaling-stroke');
|
||||
}
|
||||
emit('transform', transformItem(item));
|
||||
emit('d', item.path);
|
||||
}
|
||||
|
||||
function path(context, item) {
|
||||
var path = item.path;
|
||||
if (path == null) return true;
|
||||
|
||||
var x = item.x || 0,
|
||||
y = item.y || 0,
|
||||
sx = item.scaleX || 1,
|
||||
sy = item.scaleY || 1,
|
||||
a = (item.angle || 0) * DegToRad,
|
||||
cache = item.pathCache;
|
||||
|
||||
if (!cache || cache.path !== path) {
|
||||
(item.pathCache = cache = pathParse(path)).path = path;
|
||||
}
|
||||
|
||||
if (a && context.rotate && context.translate) {
|
||||
context.translate(x, y);
|
||||
context.rotate(a);
|
||||
pathRender(context, cache, 0, 0, sx, sy);
|
||||
context.rotate(-a);
|
||||
context.translate(-x, -y);
|
||||
} else {
|
||||
pathRender(context, cache, x, y, sx, sy);
|
||||
}
|
||||
}
|
||||
|
||||
function bound(bounds, item) {
|
||||
path(context(bounds), item)
|
||||
? bounds.set(0, 0, 0, 0)
|
||||
: boundStroke(bounds, item, true);
|
||||
|
||||
if (item.angle) {
|
||||
bounds.rotate(item.angle * DegToRad, item.x || 0, item.y || 0);
|
||||
}
|
||||
|
||||
return bounds;
|
||||
}
|
||||
|
||||
export default {
|
||||
type: 'path',
|
||||
tag: 'path',
|
||||
nested: false,
|
||||
attr: attr,
|
||||
bound: bound,
|
||||
draw: drawAll(path),
|
||||
pick: pickPath(path),
|
||||
isect: intersectPath(path)
|
||||
};
|
||||
35
node_modules/vega-scenegraph/src/marks/rect.js
generated
vendored
Normal file
35
node_modules/vega-scenegraph/src/marks/rect.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
import boundStroke from '../bound/boundStroke';
|
||||
import {rectangle} from '../path/shapes';
|
||||
import {intersectRect} from '../util/intersect';
|
||||
import {drawAll} from '../util/canvas/draw';
|
||||
import {pickPath} from '../util/canvas/pick';
|
||||
|
||||
function attr(emit, item) {
|
||||
emit('d', rectangle(null, item));
|
||||
}
|
||||
|
||||
function bound(bounds, item) {
|
||||
var x, y;
|
||||
return boundStroke(bounds.set(
|
||||
x = item.x || 0,
|
||||
y = item.y || 0,
|
||||
(x + item.width) || 0,
|
||||
(y + item.height) || 0
|
||||
), item);
|
||||
}
|
||||
|
||||
function draw(context, item) {
|
||||
context.beginPath();
|
||||
rectangle(context, item);
|
||||
}
|
||||
|
||||
export default {
|
||||
type: 'rect',
|
||||
tag: 'path',
|
||||
nested: false,
|
||||
attr: attr,
|
||||
bound: bound,
|
||||
draw: drawAll(draw),
|
||||
pick: pickPath(draw),
|
||||
isect: intersectRect
|
||||
};
|
||||
66
node_modules/vega-scenegraph/src/marks/rule.js
generated
vendored
Normal file
66
node_modules/vega-scenegraph/src/marks/rule.js
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
import boundStroke from '../bound/boundStroke';
|
||||
import {intersectRule} from '../util/intersect';
|
||||
import {visit} from '../util/visit';
|
||||
import blend from '../util/canvas/blend';
|
||||
import {pick} from '../util/canvas/pick';
|
||||
import stroke from '../util/canvas/stroke';
|
||||
import {translateItem} from '../util/svg/transform';
|
||||
|
||||
function attr(emit, item) {
|
||||
emit('transform', translateItem(item));
|
||||
emit('x2', item.x2 != null ? item.x2 - (item.x || 0) : 0);
|
||||
emit('y2', item.y2 != null ? item.y2 - (item.y || 0) : 0);
|
||||
}
|
||||
|
||||
function bound(bounds, item) {
|
||||
var x1, y1;
|
||||
return boundStroke(bounds.set(
|
||||
x1 = item.x || 0,
|
||||
y1 = item.y || 0,
|
||||
item.x2 != null ? item.x2 : x1,
|
||||
item.y2 != null ? item.y2 : y1
|
||||
), item);
|
||||
}
|
||||
|
||||
function path(context, item, opacity) {
|
||||
var x1, y1, x2, y2;
|
||||
|
||||
if (item.stroke && stroke(context, item, opacity)) {
|
||||
x1 = item.x || 0;
|
||||
y1 = item.y || 0;
|
||||
x2 = item.x2 != null ? item.x2 : x1;
|
||||
y2 = item.y2 != null ? item.y2 : y1;
|
||||
context.beginPath();
|
||||
context.moveTo(x1, y1);
|
||||
context.lineTo(x2, y2);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function draw(context, scene, bounds) {
|
||||
visit(scene, function(item) {
|
||||
if (bounds && !bounds.intersects(item.bounds)) return; // bounds check
|
||||
var opacity = item.opacity == null ? 1 : item.opacity;
|
||||
if (opacity && path(context, item, opacity)) {
|
||||
blend(context, item);
|
||||
context.stroke();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function hit(context, item, x, y) {
|
||||
if (!context.isPointInStroke) return false;
|
||||
return path(context, item, 1) && context.isPointInStroke(x, y);
|
||||
}
|
||||
|
||||
export default {
|
||||
type: 'rule',
|
||||
tag: 'line',
|
||||
nested: false,
|
||||
attr: attr,
|
||||
bound: bound,
|
||||
draw: draw,
|
||||
pick: pick(hit),
|
||||
isect: intersectRule
|
||||
};
|
||||
4
node_modules/vega-scenegraph/src/marks/shape.js
generated
vendored
Normal file
4
node_modules/vega-scenegraph/src/marks/shape.js
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import {shape} from '../path/shapes';
|
||||
import markItemPath from './markItemPath';
|
||||
|
||||
export default markItemPath('shape', shape);
|
||||
5
node_modules/vega-scenegraph/src/marks/symbol.js
generated
vendored
Normal file
5
node_modules/vega-scenegraph/src/marks/symbol.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import {symbol} from '../path/shapes';
|
||||
import {intersectPoint} from '../util/intersect';
|
||||
import markItemPath from './markItemPath';
|
||||
|
||||
export default markItemPath('symbol', symbol, intersectPoint);
|
||||
184
node_modules/vega-scenegraph/src/marks/text.js
generated
vendored
Normal file
184
node_modules/vega-scenegraph/src/marks/text.js
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
import Bounds from '../Bounds';
|
||||
import {DegToRad, HalfPi} from '../util/constants';
|
||||
import {font, lineHeight, offset, textLines, textMetrics, textValue} from '../util/text';
|
||||
import {intersectBoxLine} from '../util/intersect';
|
||||
import {visit} from '../util/visit';
|
||||
import blend from '../util/canvas/blend';
|
||||
import fill from '../util/canvas/fill';
|
||||
import {pick} from '../util/canvas/pick';
|
||||
import stroke from '../util/canvas/stroke';
|
||||
import {rotate, translate} from '../util/svg/transform';
|
||||
import {isArray} from 'vega-util';
|
||||
|
||||
var textAlign = {
|
||||
'left': 'start',
|
||||
'center': 'middle',
|
||||
'right': 'end'
|
||||
};
|
||||
|
||||
var tempBounds = new Bounds();
|
||||
|
||||
function anchorPoint(item) {
|
||||
var x = item.x || 0,
|
||||
y = item.y || 0,
|
||||
r = item.radius || 0, t;
|
||||
|
||||
if (r) {
|
||||
t = (item.theta || 0) - HalfPi;
|
||||
x += r * Math.cos(t);
|
||||
y += r * Math.sin(t);
|
||||
}
|
||||
|
||||
tempBounds.x1 = x;
|
||||
tempBounds.y1 = y;
|
||||
return tempBounds;
|
||||
}
|
||||
|
||||
function attr(emit, item) {
|
||||
var dx = item.dx || 0,
|
||||
dy = (item.dy || 0) + offset(item),
|
||||
p = anchorPoint(item),
|
||||
x = p.x1,
|
||||
y = p.y1,
|
||||
a = item.angle || 0, t;
|
||||
|
||||
emit('text-anchor', textAlign[item.align] || 'start');
|
||||
|
||||
if (a) {
|
||||
t = translate(x, y) + ' ' + rotate(a);
|
||||
if (dx || dy) t += ' ' + translate(dx, dy);
|
||||
} else {
|
||||
t = translate(x + dx, y + dy);
|
||||
}
|
||||
emit('transform', t);
|
||||
}
|
||||
|
||||
function bound(bounds, item, mode) {
|
||||
var h = textMetrics.height(item),
|
||||
a = item.align,
|
||||
p = anchorPoint(item),
|
||||
x = p.x1,
|
||||
y = p.y1,
|
||||
dx = item.dx || 0,
|
||||
dy = (item.dy || 0) + offset(item) - Math.round(0.8*h), // use 4/5 offset
|
||||
tl = textLines(item),
|
||||
w;
|
||||
|
||||
// get dimensions
|
||||
if (isArray(tl)) {
|
||||
// multi-line text
|
||||
h += lineHeight(item) * (tl.length - 1);
|
||||
w = tl.reduce((w, t) => Math.max(w, textMetrics.width(item, t)), 0);
|
||||
} else {
|
||||
// single-line text
|
||||
w = textMetrics.width(item, tl);
|
||||
}
|
||||
|
||||
// horizontal alignment
|
||||
if (a === 'center') {
|
||||
dx -= (w / 2);
|
||||
} else if (a === 'right') {
|
||||
dx -= w;
|
||||
} else {
|
||||
// left by default, do nothing
|
||||
}
|
||||
|
||||
bounds.set(dx+=x, dy+=y, dx+w, dy+h);
|
||||
|
||||
if (item.angle && !mode) {
|
||||
bounds.rotate(item.angle * DegToRad, x, y);
|
||||
} else if (mode === 2) {
|
||||
return bounds.rotatedPoints(item.angle * DegToRad, x, y);
|
||||
}
|
||||
return bounds;
|
||||
}
|
||||
|
||||
function draw(context, scene, bounds) {
|
||||
visit(scene, function(item) {
|
||||
var opacity = item.opacity == null ? 1 : item.opacity,
|
||||
p, x, y, i, lh, tl, str;
|
||||
|
||||
if (bounds && !bounds.intersects(item.bounds) || // bounds check
|
||||
opacity === 0 || item.fontSize <= 0 ||
|
||||
item.text == null || item.text.length === 0) return;
|
||||
|
||||
context.font = font(item);
|
||||
context.textAlign = item.align || 'left';
|
||||
|
||||
p = anchorPoint(item);
|
||||
x = p.x1,
|
||||
y = p.y1;
|
||||
|
||||
if (item.angle) {
|
||||
context.save();
|
||||
context.translate(x, y);
|
||||
context.rotate(item.angle * DegToRad);
|
||||
x = y = 0; // reset x, y
|
||||
}
|
||||
x += (item.dx || 0);
|
||||
y += (item.dy || 0) + offset(item);
|
||||
|
||||
tl = textLines(item);
|
||||
blend(context, item);
|
||||
if (isArray(tl)) {
|
||||
lh = lineHeight(item);
|
||||
for (i=0; i<tl.length; ++i) {
|
||||
str = textValue(item, tl[i]);
|
||||
if (item.fill && fill(context, item, opacity)) {
|
||||
context.fillText(str, x, y);
|
||||
}
|
||||
if (item.stroke && stroke(context, item, opacity)) {
|
||||
context.strokeText(str, x, y);
|
||||
}
|
||||
y += lh;
|
||||
}
|
||||
} else {
|
||||
str = textValue(item, tl);
|
||||
if (item.fill && fill(context, item, opacity)) {
|
||||
context.fillText(str, x, y);
|
||||
}
|
||||
if (item.stroke && stroke(context, item, opacity)) {
|
||||
context.strokeText(str, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
if (item.angle) context.restore();
|
||||
});
|
||||
}
|
||||
|
||||
function hit(context, item, x, y, gx, gy) {
|
||||
if (item.fontSize <= 0) return false;
|
||||
if (!item.angle) return true; // bounds sufficient if no rotation
|
||||
|
||||
// project point into space of unrotated bounds
|
||||
var p = anchorPoint(item),
|
||||
ax = p.x1,
|
||||
ay = p.y1,
|
||||
b = bound(tempBounds, item, 1),
|
||||
a = -item.angle * DegToRad,
|
||||
cos = Math.cos(a),
|
||||
sin = Math.sin(a),
|
||||
px = cos * gx - sin * gy + (ax - cos * ax + sin * ay),
|
||||
py = sin * gx + cos * gy + (ay - sin * ax - cos * ay);
|
||||
|
||||
return b.contains(px, py);
|
||||
}
|
||||
|
||||
function intersectText(item, box) {
|
||||
var p = bound(tempBounds, item, 2);
|
||||
return intersectBoxLine(box, p[0], p[1], p[2], p[3])
|
||||
|| intersectBoxLine(box, p[0], p[1], p[4], p[5])
|
||||
|| intersectBoxLine(box, p[4], p[5], p[6], p[7])
|
||||
|| intersectBoxLine(box, p[2], p[3], p[6], p[7]);
|
||||
}
|
||||
|
||||
export default {
|
||||
type: 'text',
|
||||
tag: 'text',
|
||||
nested: false,
|
||||
attr: attr,
|
||||
bound: bound,
|
||||
draw: draw,
|
||||
pick: pick(hit),
|
||||
isect: intersectText
|
||||
};
|
||||
5
node_modules/vega-scenegraph/src/marks/trail.js
generated
vendored
Normal file
5
node_modules/vega-scenegraph/src/marks/trail.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import {trail} from '../path/shapes';
|
||||
import {pickTrail} from '../util/pickPath';
|
||||
import markMultiItemPath from './markMultiItemPath';
|
||||
|
||||
export default markMultiItemPath('trail', trail, pickTrail);
|
||||
43
node_modules/vega-scenegraph/src/modules.js
generated
vendored
Normal file
43
node_modules/vega-scenegraph/src/modules.js
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
import CanvasHandler from './CanvasHandler';
|
||||
import CanvasRenderer from './CanvasRenderer';
|
||||
import SVGHandler from './SVGHandler';
|
||||
import SVGRenderer from './SVGRenderer';
|
||||
import SVGStringRenderer from './SVGStringRenderer';
|
||||
|
||||
var Canvas = 'canvas';
|
||||
var PNG = 'png';
|
||||
var SVG = 'svg';
|
||||
var None = 'none';
|
||||
|
||||
export var RenderType = {
|
||||
Canvas: Canvas,
|
||||
PNG: PNG,
|
||||
SVG: SVG,
|
||||
None: None
|
||||
};
|
||||
|
||||
var modules = {};
|
||||
|
||||
modules[Canvas] = modules[PNG] = {
|
||||
renderer: CanvasRenderer,
|
||||
headless: CanvasRenderer,
|
||||
handler: CanvasHandler
|
||||
};
|
||||
|
||||
modules[SVG] = {
|
||||
renderer: SVGRenderer,
|
||||
headless: SVGStringRenderer,
|
||||
handler: SVGHandler
|
||||
};
|
||||
|
||||
modules[None] = {};
|
||||
|
||||
export function renderModule(name, _) {
|
||||
name = String(name || '').toLowerCase();
|
||||
if (arguments.length > 1) {
|
||||
modules[name] = _;
|
||||
return this;
|
||||
} else {
|
||||
return modules[name];
|
||||
}
|
||||
}
|
||||
107
node_modules/vega-scenegraph/src/path/arc.js
generated
vendored
Normal file
107
node_modules/vega-scenegraph/src/path/arc.js
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
import {DegToRad, HalfPi, Tau} from '../util/constants';
|
||||
|
||||
export var segmentCache = {};
|
||||
export var bezierCache = {};
|
||||
|
||||
var join = [].join;
|
||||
|
||||
// Copied from Inkscape svgtopdf, thanks!
|
||||
export function segments(x, y, rx, ry, large, sweep, rotateX, ox, oy) {
|
||||
var key = join.call(arguments);
|
||||
if (segmentCache[key]) {
|
||||
return segmentCache[key];
|
||||
}
|
||||
|
||||
var th = rotateX * DegToRad;
|
||||
var sin_th = Math.sin(th);
|
||||
var cos_th = Math.cos(th);
|
||||
rx = Math.abs(rx);
|
||||
ry = Math.abs(ry);
|
||||
var px = cos_th * (ox - x) * 0.5 + sin_th * (oy - y) * 0.5;
|
||||
var py = cos_th * (oy - y) * 0.5 - sin_th * (ox - x) * 0.5;
|
||||
var pl = (px*px) / (rx*rx) + (py*py) / (ry*ry);
|
||||
if (pl > 1) {
|
||||
pl = Math.sqrt(pl);
|
||||
rx *= pl;
|
||||
ry *= pl;
|
||||
}
|
||||
|
||||
var a00 = cos_th / rx;
|
||||
var a01 = sin_th / rx;
|
||||
var a10 = (-sin_th) / ry;
|
||||
var a11 = (cos_th) / ry;
|
||||
var x0 = a00 * ox + a01 * oy;
|
||||
var y0 = a10 * ox + a11 * oy;
|
||||
var x1 = a00 * x + a01 * y;
|
||||
var y1 = a10 * x + a11 * y;
|
||||
|
||||
var d = (x1-x0) * (x1-x0) + (y1-y0) * (y1-y0);
|
||||
var sfactor_sq = 1 / d - 0.25;
|
||||
if (sfactor_sq < 0) sfactor_sq = 0;
|
||||
var sfactor = Math.sqrt(sfactor_sq);
|
||||
if (sweep == large) sfactor = -sfactor;
|
||||
var xc = 0.5 * (x0 + x1) - sfactor * (y1-y0);
|
||||
var yc = 0.5 * (y0 + y1) + sfactor * (x1-x0);
|
||||
|
||||
var th0 = Math.atan2(y0-yc, x0-xc);
|
||||
var th1 = Math.atan2(y1-yc, x1-xc);
|
||||
|
||||
var th_arc = th1-th0;
|
||||
if (th_arc < 0 && sweep === 1) {
|
||||
th_arc += Tau;
|
||||
} else if (th_arc > 0 && sweep === 0) {
|
||||
th_arc -= Tau;
|
||||
}
|
||||
|
||||
var segs = Math.ceil(Math.abs(th_arc / (HalfPi + 0.001)));
|
||||
var result = [];
|
||||
for (var i=0; i<segs; ++i) {
|
||||
var th2 = th0 + i * th_arc / segs;
|
||||
var th3 = th0 + (i+1) * th_arc / segs;
|
||||
result[i] = [xc, yc, th2, th3, rx, ry, sin_th, cos_th];
|
||||
}
|
||||
|
||||
return (segmentCache[key] = result);
|
||||
}
|
||||
|
||||
export function bezier(params) {
|
||||
var key = join.call(params);
|
||||
if (bezierCache[key]) {
|
||||
return bezierCache[key];
|
||||
}
|
||||
|
||||
var cx = params[0],
|
||||
cy = params[1],
|
||||
th0 = params[2],
|
||||
th1 = params[3],
|
||||
rx = params[4],
|
||||
ry = params[5],
|
||||
sin_th = params[6],
|
||||
cos_th = params[7];
|
||||
|
||||
var a00 = cos_th * rx;
|
||||
var a01 = -sin_th * ry;
|
||||
var a10 = sin_th * rx;
|
||||
var a11 = cos_th * ry;
|
||||
|
||||
var cos_th0 = Math.cos(th0);
|
||||
var sin_th0 = Math.sin(th0);
|
||||
var cos_th1 = Math.cos(th1);
|
||||
var sin_th1 = Math.sin(th1);
|
||||
|
||||
var th_half = 0.5 * (th1 - th0);
|
||||
var sin_th_h2 = Math.sin(th_half * 0.5);
|
||||
var t = (8/3) * sin_th_h2 * sin_th_h2 / Math.sin(th_half);
|
||||
var x1 = cx + cos_th0 - t * sin_th0;
|
||||
var y1 = cy + sin_th0 + t * cos_th0;
|
||||
var x3 = cx + cos_th1;
|
||||
var y3 = cy + sin_th1;
|
||||
var x2 = x3 + t * sin_th1;
|
||||
var y2 = y3 - t * cos_th1;
|
||||
|
||||
return (bezierCache[key] = [
|
||||
a00 * x1 + a01 * y1, a10 * x1 + a11 * y1,
|
||||
a00 * x2 + a01 * y2, a10 * x2 + a11 * y2,
|
||||
a00 * x3 + a01 * y3, a10 * x3 + a11 * y3
|
||||
]);
|
||||
}
|
||||
105
node_modules/vega-scenegraph/src/path/curves.js
generated
vendored
Normal file
105
node_modules/vega-scenegraph/src/path/curves.js
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
import {hasOwnProperty} from 'vega-util';
|
||||
|
||||
import {
|
||||
curveBasis,
|
||||
curveBasisClosed,
|
||||
curveBasisOpen,
|
||||
curveBundle,
|
||||
curveCardinal,
|
||||
curveCardinalClosed,
|
||||
curveCardinalOpen,
|
||||
curveCatmullRom,
|
||||
curveCatmullRomClosed,
|
||||
curveCatmullRomOpen,
|
||||
curveLinear,
|
||||
curveLinearClosed,
|
||||
curveMonotoneX,
|
||||
curveMonotoneY,
|
||||
curveNatural,
|
||||
curveStep,
|
||||
curveStepAfter,
|
||||
curveStepBefore
|
||||
} from 'd3-shape';
|
||||
|
||||
var lookup = {
|
||||
'basis': {
|
||||
curve: curveBasis
|
||||
},
|
||||
'basis-closed': {
|
||||
curve: curveBasisClosed
|
||||
},
|
||||
'basis-open': {
|
||||
curve: curveBasisOpen
|
||||
},
|
||||
'bundle': {
|
||||
curve: curveBundle,
|
||||
tension: 'beta',
|
||||
value: 0.85
|
||||
},
|
||||
'cardinal': {
|
||||
curve: curveCardinal,
|
||||
tension: 'tension',
|
||||
value: 0
|
||||
},
|
||||
'cardinal-open': {
|
||||
curve: curveCardinalOpen,
|
||||
tension: 'tension',
|
||||
value: 0
|
||||
},
|
||||
'cardinal-closed': {
|
||||
curve: curveCardinalClosed,
|
||||
tension: 'tension',
|
||||
value: 0
|
||||
},
|
||||
'catmull-rom': {
|
||||
curve: curveCatmullRom,
|
||||
tension: 'alpha',
|
||||
value: 0.5
|
||||
},
|
||||
'catmull-rom-closed': {
|
||||
curve: curveCatmullRomClosed,
|
||||
tension: 'alpha',
|
||||
value: 0.5
|
||||
},
|
||||
'catmull-rom-open': {
|
||||
curve: curveCatmullRomOpen,
|
||||
tension: 'alpha',
|
||||
value: 0.5
|
||||
},
|
||||
'linear': {
|
||||
curve: curveLinear
|
||||
},
|
||||
'linear-closed': {
|
||||
curve: curveLinearClosed
|
||||
},
|
||||
'monotone': {
|
||||
horizontal: curveMonotoneY,
|
||||
vertical: curveMonotoneX
|
||||
},
|
||||
'natural': {
|
||||
curve: curveNatural
|
||||
},
|
||||
'step': {
|
||||
curve: curveStep
|
||||
},
|
||||
'step-after': {
|
||||
curve: curveStepAfter
|
||||
},
|
||||
'step-before': {
|
||||
curve: curveStepBefore
|
||||
}
|
||||
};
|
||||
|
||||
export default function curves(type, orientation, tension) {
|
||||
var entry = hasOwnProperty(lookup, type) && lookup[type],
|
||||
curve = null;
|
||||
|
||||
if (entry) {
|
||||
curve = entry.curve || entry[orientation || 'vertical'];
|
||||
if (entry.tension && tension != null) {
|
||||
curve = curve[entry.tension](tension);
|
||||
}
|
||||
}
|
||||
|
||||
return curve;
|
||||
}
|
||||
49
node_modules/vega-scenegraph/src/path/parse.js
generated
vendored
Normal file
49
node_modules/vega-scenegraph/src/path/parse.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
// Path parsing and rendering code adapted from fabric.js -- Thanks!
|
||||
var cmdlen = { m:2, l:2, h:1, v:1, c:6, s:4, q:4, t:2, a:7 },
|
||||
regexp = [/([MLHVCSQTAZmlhvcsqtaz])/g, /###/, /(\d)([-+])/g, /\s|,|###/];
|
||||
|
||||
export default function(pathstr) {
|
||||
var result = [],
|
||||
path,
|
||||
curr,
|
||||
chunks,
|
||||
parsed, param,
|
||||
cmd, len, i, j, n, m;
|
||||
|
||||
// First, break path into command sequence
|
||||
path = pathstr
|
||||
.slice()
|
||||
.replace(regexp[0], '###$1')
|
||||
.split(regexp[1])
|
||||
.slice(1);
|
||||
|
||||
// Next, parse each command in turn
|
||||
for (i=0, n=path.length; i<n; ++i) {
|
||||
curr = path[i];
|
||||
chunks = curr
|
||||
.slice(1)
|
||||
.trim()
|
||||
.replace(regexp[2],'$1###$2')
|
||||
.split(regexp[3]);
|
||||
cmd = curr.charAt(0);
|
||||
|
||||
parsed = [cmd];
|
||||
for (j=0, m=chunks.length; j<m; ++j) {
|
||||
if ((param = +chunks[j]) === param) { // not NaN
|
||||
parsed.push(param);
|
||||
}
|
||||
}
|
||||
|
||||
len = cmdlen[cmd.toLowerCase()];
|
||||
if (parsed.length-1 > len) {
|
||||
for (j=1, m=parsed.length; j<m; j+=len) {
|
||||
result.push([cmd].concat(parsed.slice(j, j+len)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
result.push(parsed);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
136
node_modules/vega-scenegraph/src/path/rectangle.js
generated
vendored
Normal file
136
node_modules/vega-scenegraph/src/path/rectangle.js
generated
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
import {path} from 'd3-path';
|
||||
|
||||
// See http://spencermortensen.com/articles/bezier-circle/
|
||||
const C = 0.448084975506; // C = 1 - c
|
||||
|
||||
function rectangleX(d) {
|
||||
return d.x;
|
||||
}
|
||||
|
||||
function rectangleY(d) {
|
||||
return d.y;
|
||||
}
|
||||
|
||||
function rectangleWidth(d) {
|
||||
return d.width;
|
||||
}
|
||||
|
||||
function rectangleHeight(d) {
|
||||
return d.height;
|
||||
}
|
||||
|
||||
function number(_) {
|
||||
return typeof _ === 'function' ? _ : () => +_;
|
||||
}
|
||||
|
||||
function clamp(value, min, max) {
|
||||
return Math.max(min, Math.min(value, max));
|
||||
}
|
||||
|
||||
export default function() {
|
||||
var x = rectangleX,
|
||||
y = rectangleY,
|
||||
width = rectangleWidth,
|
||||
height = rectangleHeight,
|
||||
crTL = number(0),
|
||||
crTR = crTL,
|
||||
crBL = crTL,
|
||||
crBR = crTL,
|
||||
context = null;
|
||||
|
||||
function rectangle(_, x0, y0) {
|
||||
var buffer,
|
||||
x1 = x0 != null ? x0 : +x.call(this, _),
|
||||
y1 = y0 != null ? y0 : +y.call(this, _),
|
||||
w = +width.call(this, _),
|
||||
h = +height.call(this, _),
|
||||
s = Math.min(w, h) / 2,
|
||||
tl = clamp(+crTL.call(this, _), 0, s),
|
||||
tr = clamp(+crTR.call(this, _), 0, s),
|
||||
bl = clamp(+crBL.call(this, _), 0, s),
|
||||
br = clamp(+crBR.call(this, _), 0, s);
|
||||
|
||||
if (!context) context = buffer = path();
|
||||
|
||||
if (tl <= 0 && tr <= 0 && bl <= 0 && br <= 0) {
|
||||
context.rect(x1, y1, w, h);
|
||||
} else {
|
||||
var x2 = x1 + w,
|
||||
y2 = y1 + h;
|
||||
context.moveTo(x1 + tl, y1);
|
||||
context.lineTo(x2 - tr, y1);
|
||||
context.bezierCurveTo(x2 - C * tr, y1, x2, y1 + C * tr, x2, y1 + tr);
|
||||
context.lineTo(x2, y2 - br);
|
||||
context.bezierCurveTo(x2, y2 - C * br, x2 - C * br, y2, x2 - br, y2);
|
||||
context.lineTo(x1 + bl, y2);
|
||||
context.bezierCurveTo(x1 + C * bl, y2, x1, y2 - C * bl, x1, y2 - bl);
|
||||
context.lineTo(x1, y1 + tl);
|
||||
context.bezierCurveTo(x1, y1 + C * tl, x1 + C * tl, y1, x1 + tl, y1);
|
||||
context.closePath();
|
||||
}
|
||||
|
||||
if (buffer) {
|
||||
context = null;
|
||||
return buffer + '' || null;
|
||||
}
|
||||
}
|
||||
|
||||
rectangle.x = function(_) {
|
||||
if (arguments.length) {
|
||||
x = number(_);
|
||||
return rectangle;
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
rectangle.y = function(_) {
|
||||
if (arguments.length) {
|
||||
y = number(_);
|
||||
return rectangle;
|
||||
} else {
|
||||
return y;
|
||||
}
|
||||
};
|
||||
|
||||
rectangle.width = function(_) {
|
||||
if (arguments.length) {
|
||||
width = number(_);
|
||||
return rectangle;
|
||||
} else {
|
||||
return width;
|
||||
}
|
||||
};
|
||||
|
||||
rectangle.height = function(_) {
|
||||
if (arguments.length) {
|
||||
height = number(_);
|
||||
return rectangle;
|
||||
} else {
|
||||
return height;
|
||||
}
|
||||
};
|
||||
|
||||
rectangle.cornerRadius = function(tl, tr, br, bl) {
|
||||
if (arguments.length) {
|
||||
crTL = number(tl);
|
||||
crTR = tr != null ? number(tr) : crTL;
|
||||
crBR = br != null ? number(br) : crTL;
|
||||
crBL = bl != null ? number(bl) : crTR;
|
||||
return rectangle;
|
||||
} else {
|
||||
return crTL;
|
||||
}
|
||||
};
|
||||
|
||||
rectangle.context = function(_) {
|
||||
if (arguments.length) {
|
||||
context = _ == null ? null : _;
|
||||
return rectangle;
|
||||
} else {
|
||||
return context;
|
||||
}
|
||||
};
|
||||
|
||||
return rectangle;
|
||||
}
|
||||
323
node_modules/vega-scenegraph/src/path/render.js
generated
vendored
Normal file
323
node_modules/vega-scenegraph/src/path/render.js
generated
vendored
Normal file
@@ -0,0 +1,323 @@
|
||||
import {bezier, segments} from './arc';
|
||||
|
||||
var temp = ['l', 0, 0, 0, 0, 0, 0, 0];
|
||||
|
||||
function scale(current, sX, sY) {
|
||||
var c = (temp[0] = current[0]);
|
||||
if (c === 'a' || c === 'A') {
|
||||
temp[1] = sX * current[1];
|
||||
temp[2] = sY * current[2];
|
||||
temp[3] = current[3];
|
||||
temp[4] = current[4];
|
||||
temp[5] = current[5];
|
||||
temp[6] = sX * current[6];
|
||||
temp[7] = sY * current[7];
|
||||
} else if (c === 'h' || c === 'H') {
|
||||
temp[1] = sX * current[1];
|
||||
} else if (c === 'v' || c === 'V') {
|
||||
temp[1] = sY * current[1];
|
||||
} else {
|
||||
for (var i=1, n=current.length; i<n; ++i) {
|
||||
temp[i] = (i % 2 == 1 ? sX : sY) * current[i];
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
export default function(context, path, l, t, sX, sY) {
|
||||
var current, // current instruction
|
||||
previous = null,
|
||||
x = 0, // current x
|
||||
y = 0, // current y
|
||||
controlX = 0, // current control point x
|
||||
controlY = 0, // current control point y
|
||||
tempX,
|
||||
tempY,
|
||||
tempControlX,
|
||||
tempControlY;
|
||||
|
||||
if (l == null) l = 0;
|
||||
if (t == null) t = 0;
|
||||
if (sX == null) sX = 1;
|
||||
if (sY == null) sY = sX;
|
||||
|
||||
if (context.beginPath) context.beginPath();
|
||||
|
||||
for (var i=0, len=path.length; i<len; ++i) {
|
||||
current = path[i];
|
||||
if (sX !== 1 || sY !== 1) {
|
||||
current = scale(current, sX, sY);
|
||||
}
|
||||
|
||||
switch (current[0]) { // first letter
|
||||
|
||||
case 'l': // lineto, relative
|
||||
x += current[1];
|
||||
y += current[2];
|
||||
context.lineTo(x + l, y + t);
|
||||
break;
|
||||
|
||||
case 'L': // lineto, absolute
|
||||
x = current[1];
|
||||
y = current[2];
|
||||
context.lineTo(x + l, y + t);
|
||||
break;
|
||||
|
||||
case 'h': // horizontal lineto, relative
|
||||
x += current[1];
|
||||
context.lineTo(x + l, y + t);
|
||||
break;
|
||||
|
||||
case 'H': // horizontal lineto, absolute
|
||||
x = current[1];
|
||||
context.lineTo(x + l, y + t);
|
||||
break;
|
||||
|
||||
case 'v': // vertical lineto, relative
|
||||
y += current[1];
|
||||
context.lineTo(x + l, y + t);
|
||||
break;
|
||||
|
||||
case 'V': // verical lineto, absolute
|
||||
y = current[1];
|
||||
context.lineTo(x + l, y + t);
|
||||
break;
|
||||
|
||||
case 'm': // moveTo, relative
|
||||
x += current[1];
|
||||
y += current[2];
|
||||
context.moveTo(x + l, y + t);
|
||||
break;
|
||||
|
||||
case 'M': // moveTo, absolute
|
||||
x = current[1];
|
||||
y = current[2];
|
||||
context.moveTo(x + l, y + t);
|
||||
break;
|
||||
|
||||
case 'c': // bezierCurveTo, relative
|
||||
tempX = x + current[5];
|
||||
tempY = y + current[6];
|
||||
controlX = x + current[3];
|
||||
controlY = y + current[4];
|
||||
context.bezierCurveTo(
|
||||
x + current[1] + l, // x1
|
||||
y + current[2] + t, // y1
|
||||
controlX + l, // x2
|
||||
controlY + t, // y2
|
||||
tempX + l,
|
||||
tempY + t
|
||||
);
|
||||
x = tempX;
|
||||
y = tempY;
|
||||
break;
|
||||
|
||||
case 'C': // bezierCurveTo, absolute
|
||||
x = current[5];
|
||||
y = current[6];
|
||||
controlX = current[3];
|
||||
controlY = current[4];
|
||||
context.bezierCurveTo(
|
||||
current[1] + l,
|
||||
current[2] + t,
|
||||
controlX + l,
|
||||
controlY + t,
|
||||
x + l,
|
||||
y + t
|
||||
);
|
||||
break;
|
||||
|
||||
case 's': // shorthand cubic bezierCurveTo, relative
|
||||
// transform to absolute x,y
|
||||
tempX = x + current[3];
|
||||
tempY = y + current[4];
|
||||
// calculate reflection of previous control points
|
||||
controlX = 2 * x - controlX;
|
||||
controlY = 2 * y - controlY;
|
||||
context.bezierCurveTo(
|
||||
controlX + l,
|
||||
controlY + t,
|
||||
x + current[1] + l,
|
||||
y + current[2] + t,
|
||||
tempX + l,
|
||||
tempY + t
|
||||
);
|
||||
|
||||
// set control point to 2nd one of this command
|
||||
// the first control point is assumed to be the reflection of
|
||||
// the second control point on the previous command relative
|
||||
// to the current point.
|
||||
controlX = x + current[1];
|
||||
controlY = y + current[2];
|
||||
|
||||
x = tempX;
|
||||
y = tempY;
|
||||
break;
|
||||
|
||||
case 'S': // shorthand cubic bezierCurveTo, absolute
|
||||
tempX = current[3];
|
||||
tempY = current[4];
|
||||
// calculate reflection of previous control points
|
||||
controlX = 2*x - controlX;
|
||||
controlY = 2*y - controlY;
|
||||
context.bezierCurveTo(
|
||||
controlX + l,
|
||||
controlY + t,
|
||||
current[1] + l,
|
||||
current[2] + t,
|
||||
tempX + l,
|
||||
tempY + t
|
||||
);
|
||||
x = tempX;
|
||||
y = tempY;
|
||||
// set control point to 2nd one of this command
|
||||
// the first control point is assumed to be the reflection of
|
||||
// the second control point on the previous command relative
|
||||
// to the current point.
|
||||
controlX = current[1];
|
||||
controlY = current[2];
|
||||
|
||||
break;
|
||||
|
||||
case 'q': // quadraticCurveTo, relative
|
||||
// transform to absolute x,y
|
||||
tempX = x + current[3];
|
||||
tempY = y + current[4];
|
||||
|
||||
controlX = x + current[1];
|
||||
controlY = y + current[2];
|
||||
|
||||
context.quadraticCurveTo(
|
||||
controlX + l,
|
||||
controlY + t,
|
||||
tempX + l,
|
||||
tempY + t
|
||||
);
|
||||
x = tempX;
|
||||
y = tempY;
|
||||
break;
|
||||
|
||||
case 'Q': // quadraticCurveTo, absolute
|
||||
tempX = current[3];
|
||||
tempY = current[4];
|
||||
|
||||
context.quadraticCurveTo(
|
||||
current[1] + l,
|
||||
current[2] + t,
|
||||
tempX + l,
|
||||
tempY + t
|
||||
);
|
||||
x = tempX;
|
||||
y = tempY;
|
||||
controlX = current[1];
|
||||
controlY = current[2];
|
||||
break;
|
||||
|
||||
case 't': // shorthand quadraticCurveTo, relative
|
||||
|
||||
// transform to absolute x,y
|
||||
tempX = x + current[1];
|
||||
tempY = y + current[2];
|
||||
|
||||
if (previous[0].match(/[QqTt]/) === null) {
|
||||
// If there is no previous command or if the previous command was not a Q, q, T or t,
|
||||
// assume the control point is coincident with the current point
|
||||
controlX = x;
|
||||
controlY = y;
|
||||
}
|
||||
else if (previous[0] === 't') {
|
||||
// calculate reflection of previous control points for t
|
||||
controlX = 2 * x - tempControlX;
|
||||
controlY = 2 * y - tempControlY;
|
||||
}
|
||||
else if (previous[0] === 'q') {
|
||||
// calculate reflection of previous control points for q
|
||||
controlX = 2 * x - controlX;
|
||||
controlY = 2 * y - controlY;
|
||||
}
|
||||
|
||||
tempControlX = controlX;
|
||||
tempControlY = controlY;
|
||||
|
||||
context.quadraticCurveTo(
|
||||
controlX + l,
|
||||
controlY + t,
|
||||
tempX + l,
|
||||
tempY + t
|
||||
);
|
||||
x = tempX;
|
||||
y = tempY;
|
||||
controlX = x + current[1];
|
||||
controlY = y + current[2];
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
tempX = current[1];
|
||||
tempY = current[2];
|
||||
|
||||
// calculate reflection of previous control points
|
||||
controlX = 2 * x - controlX;
|
||||
controlY = 2 * y - controlY;
|
||||
context.quadraticCurveTo(
|
||||
controlX + l,
|
||||
controlY + t,
|
||||
tempX + l,
|
||||
tempY + t
|
||||
);
|
||||
x = tempX;
|
||||
y = tempY;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
drawArc(context, x + l, y + t, [
|
||||
current[1],
|
||||
current[2],
|
||||
current[3],
|
||||
current[4],
|
||||
current[5],
|
||||
current[6] + x + l,
|
||||
current[7] + y + t
|
||||
]);
|
||||
x += current[6];
|
||||
y += current[7];
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
drawArc(context, x + l, y + t, [
|
||||
current[1],
|
||||
current[2],
|
||||
current[3],
|
||||
current[4],
|
||||
current[5],
|
||||
current[6] + l,
|
||||
current[7] + t
|
||||
]);
|
||||
x = current[6];
|
||||
y = current[7];
|
||||
break;
|
||||
|
||||
case 'z':
|
||||
case 'Z':
|
||||
context.closePath();
|
||||
break;
|
||||
}
|
||||
previous = current;
|
||||
}
|
||||
}
|
||||
|
||||
function drawArc(context, x, y, coords) {
|
||||
var seg = segments(
|
||||
coords[5], // end x
|
||||
coords[6], // end y
|
||||
coords[0], // radius x
|
||||
coords[1], // radius y
|
||||
coords[3], // large flag
|
||||
coords[4], // sweep flag
|
||||
coords[2], // rotation
|
||||
x, y
|
||||
);
|
||||
for (var i=0; i<seg.length; ++i) {
|
||||
var bez = bezier(seg[i]);
|
||||
context.bezierCurveTo(bez[0], bez[1], bez[2], bez[3], bez[4], bez[5]);
|
||||
}
|
||||
}
|
||||
91
node_modules/vega-scenegraph/src/path/shapes.js
generated
vendored
Normal file
91
node_modules/vega-scenegraph/src/path/shapes.js
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
import curves from './curves';
|
||||
import symbols from './symbols';
|
||||
|
||||
import {default as vg_rect} from './rectangle';
|
||||
import {default as vg_trail} from './trail';
|
||||
|
||||
import {
|
||||
arc as d3_arc,
|
||||
area as d3_area,
|
||||
line as d3_line,
|
||||
symbol as d3_symbol
|
||||
} from 'd3-shape';
|
||||
|
||||
function value(a, b) {
|
||||
return a != null ? a : b;
|
||||
}
|
||||
|
||||
const x = item => item.x || 0,
|
||||
y = item => item.y || 0,
|
||||
w = item => item.width || 0,
|
||||
h = item => item.height || 0,
|
||||
xw = item => (item.x || 0) + (item.width || 0),
|
||||
yh = item => (item.y || 0) + (item.height || 0),
|
||||
sa = item => item.startAngle || 0,
|
||||
ea = item => item.endAngle || 0,
|
||||
pa = item => item.padAngle || 0,
|
||||
ir = item => item.innerRadius || 0,
|
||||
or = item => item.outerRadius || 0,
|
||||
cr = item => item.cornerRadius || 0,
|
||||
tl = item => value(item.cornerRadiusTopLeft, item.cornerRadius) || 0,
|
||||
tr = item => value(item.cornerRadiusTopRight, item.cornerRadius) || 0,
|
||||
br = item => value(item.cornerRadiusBottomRight, item.cornerRadius) || 0,
|
||||
bl = item => value(item.cornerRadiusBottomLeft, item.cornerRadius) || 0,
|
||||
sz = item => value(item.size, 64),
|
||||
ts = item => item.size || 1,
|
||||
def = item => !(item.defined === false),
|
||||
type = item => symbols(item.shape || 'circle');
|
||||
|
||||
const arcShape = d3_arc().startAngle(sa).endAngle(ea).padAngle(pa)
|
||||
.innerRadius(ir).outerRadius(or).cornerRadius(cr),
|
||||
areavShape = d3_area().x(x).y1(y).y0(yh).defined(def),
|
||||
areahShape = d3_area().y(y).x1(x).x0(xw).defined(def),
|
||||
lineShape = d3_line().x(x).y(y).defined(def),
|
||||
rectShape = vg_rect().x(x).y(y).width(w).height(h)
|
||||
.cornerRadius(tl, tr, br, bl),
|
||||
symbolShape = d3_symbol().type(type).size(sz),
|
||||
trailShape = vg_trail().x(x).y(y).defined(def).size(ts);
|
||||
|
||||
export function hasCornerRadius(item) {
|
||||
return item.cornerRadius
|
||||
|| item.cornerRadiusTopLeft
|
||||
|| item.cornerRadiusTopRight
|
||||
|| item.cornerRadiusBottomRight
|
||||
|| item.cornerRadiusBottomLeft;
|
||||
}
|
||||
|
||||
export function arc(context, item) {
|
||||
return arcShape.context(context)(item);
|
||||
}
|
||||
|
||||
export function area(context, items) {
|
||||
var item = items[0],
|
||||
interp = item.interpolate || 'linear';
|
||||
return (item.orient === 'horizontal' ? areahShape : areavShape)
|
||||
.curve(curves(interp, item.orient, item.tension))
|
||||
.context(context)(items);
|
||||
}
|
||||
|
||||
export function line(context, items) {
|
||||
var item = items[0],
|
||||
interp = item.interpolate || 'linear';
|
||||
return lineShape.curve(curves(interp, item.orient, item.tension))
|
||||
.context(context)(items);
|
||||
}
|
||||
|
||||
export function rectangle(context, item, x, y) {
|
||||
return rectShape.context(context)(item, x, y);
|
||||
}
|
||||
|
||||
export function shape(context, item) {
|
||||
return (item.mark.shape || item.shape)
|
||||
.context(context)(item);
|
||||
}
|
||||
|
||||
export function symbol(context, item) {
|
||||
return symbolShape.context(context)(item);
|
||||
}
|
||||
|
||||
export function trail(context, items) {
|
||||
return trailShape.context(context)(items);
|
||||
}
|
||||
156
node_modules/vega-scenegraph/src/path/symbols.js
generated
vendored
Normal file
156
node_modules/vega-scenegraph/src/path/symbols.js
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
import pathParse from './parse';
|
||||
import pathRender from './render';
|
||||
import {HalfSqrt3, Tau} from '../util/constants';
|
||||
import {hasOwnProperty} from 'vega-util';
|
||||
|
||||
var Tan30 = 0.5773502691896257;
|
||||
|
||||
var builtins = {
|
||||
'circle': {
|
||||
draw: function(context, size) {
|
||||
var r = Math.sqrt(size) / 2;
|
||||
context.moveTo(r, 0);
|
||||
context.arc(0, 0, r, 0, Tau);
|
||||
}
|
||||
},
|
||||
'cross': {
|
||||
draw: function(context, size) {
|
||||
var r = Math.sqrt(size) / 2,
|
||||
s = r / 2.5;
|
||||
context.moveTo(-r, -s);
|
||||
context.lineTo(-r, s);
|
||||
context.lineTo(-s, s);
|
||||
context.lineTo(-s, r);
|
||||
context.lineTo(s, r);
|
||||
context.lineTo(s, s);
|
||||
context.lineTo(r, s);
|
||||
context.lineTo(r, -s);
|
||||
context.lineTo(s, -s);
|
||||
context.lineTo(s, -r);
|
||||
context.lineTo(-s, -r);
|
||||
context.lineTo(-s, -s);
|
||||
context.closePath();
|
||||
}
|
||||
},
|
||||
'diamond': {
|
||||
draw: function(context, size) {
|
||||
var r = Math.sqrt(size) / 2;
|
||||
context.moveTo(-r, 0);
|
||||
context.lineTo(0, -r);
|
||||
context.lineTo(r, 0);
|
||||
context.lineTo(0, r);
|
||||
context.closePath();
|
||||
}
|
||||
},
|
||||
'square': {
|
||||
draw: function(context, size) {
|
||||
var w = Math.sqrt(size),
|
||||
x = -w / 2;
|
||||
context.rect(x, x, w, w);
|
||||
}
|
||||
},
|
||||
'arrow': {
|
||||
draw: function(context, size) {
|
||||
var r = Math.sqrt(size) / 2,
|
||||
s = r / 7,
|
||||
t = r / 2.5,
|
||||
v = r / 8;
|
||||
context.moveTo(-s, r);
|
||||
context.lineTo(s, r);
|
||||
context.lineTo(s, -v);
|
||||
context.lineTo(t, -v);
|
||||
context.lineTo(0, -r);
|
||||
context.lineTo(-t, -v);
|
||||
context.lineTo(-s, -v);
|
||||
context.closePath();
|
||||
}
|
||||
},
|
||||
'wedge': {
|
||||
draw: function(context, size) {
|
||||
var r = Math.sqrt(size) / 2,
|
||||
h = HalfSqrt3 * r,
|
||||
o = (h - r * Tan30),
|
||||
b = r / 4;
|
||||
context.moveTo(0, -h - o);
|
||||
context.lineTo(-b, h - o);
|
||||
context.lineTo(b, h - o);
|
||||
context.closePath();
|
||||
}
|
||||
},
|
||||
'triangle': {
|
||||
draw: function(context, size) {
|
||||
var r = Math.sqrt(size) / 2,
|
||||
h = HalfSqrt3 * r,
|
||||
o = (h - r * Tan30);
|
||||
context.moveTo(0, -h - o);
|
||||
context.lineTo(-r, h - o);
|
||||
context.lineTo(r, h - o);
|
||||
context.closePath();
|
||||
}
|
||||
},
|
||||
'triangle-up': {
|
||||
draw: function(context, size) {
|
||||
var r = Math.sqrt(size) / 2,
|
||||
h = HalfSqrt3 * r;
|
||||
context.moveTo(0, -h);
|
||||
context.lineTo(-r, h);
|
||||
context.lineTo(r, h);
|
||||
context.closePath();
|
||||
}
|
||||
},
|
||||
'triangle-down': {
|
||||
draw: function(context, size) {
|
||||
var r = Math.sqrt(size) / 2,
|
||||
h = HalfSqrt3 * r;
|
||||
context.moveTo(0, h);
|
||||
context.lineTo(-r, -h);
|
||||
context.lineTo(r, -h);
|
||||
context.closePath();
|
||||
}
|
||||
},
|
||||
'triangle-right': {
|
||||
draw: function(context, size) {
|
||||
var r = Math.sqrt(size) / 2,
|
||||
h = HalfSqrt3 * r;
|
||||
context.moveTo(h, 0);
|
||||
context.lineTo(-h, -r);
|
||||
context.lineTo(-h, r);
|
||||
context.closePath();
|
||||
}
|
||||
},
|
||||
'triangle-left': {
|
||||
draw: function(context, size) {
|
||||
var r = Math.sqrt(size) / 2,
|
||||
h = HalfSqrt3 * r;
|
||||
context.moveTo(-h, 0);
|
||||
context.lineTo(h, -r);
|
||||
context.lineTo(h, r);
|
||||
context.closePath();
|
||||
}
|
||||
},
|
||||
'stroke': {
|
||||
draw: function(context, size) {
|
||||
var r = Math.sqrt(size) / 2;
|
||||
context.moveTo(-r, 0);
|
||||
context.lineTo(r, 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default function symbols(_) {
|
||||
return hasOwnProperty(builtins, _) ? builtins[_] : customSymbol(_);
|
||||
}
|
||||
|
||||
var custom = {};
|
||||
|
||||
function customSymbol(path) {
|
||||
if (!hasOwnProperty(custom, path)) {
|
||||
var parsed = pathParse(path);
|
||||
custom[path] = {
|
||||
draw: function(context, size) {
|
||||
pathRender(context, parsed, 0, 0, Math.sqrt(size) / 2);
|
||||
}
|
||||
};
|
||||
}
|
||||
return custom[path];
|
||||
}
|
||||
116
node_modules/vega-scenegraph/src/path/trail.js
generated
vendored
Normal file
116
node_modules/vega-scenegraph/src/path/trail.js
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
import {Tau} from '../util/constants';
|
||||
import {path} from 'd3-path';
|
||||
|
||||
export default function() {
|
||||
var x,
|
||||
y,
|
||||
size,
|
||||
defined,
|
||||
context = null,
|
||||
ready, x1, y1, r1;
|
||||
|
||||
function point(x2, y2, w2) {
|
||||
var r2 = w2 / 2;
|
||||
|
||||
if (ready) {
|
||||
var ux = y1 - y2,
|
||||
uy = x2 - x1;
|
||||
|
||||
if (ux || uy) {
|
||||
// get normal vector
|
||||
var ud = Math.sqrt(ux * ux + uy * uy),
|
||||
rx = (ux /= ud) * r1,
|
||||
ry = (uy /= ud) * r1,
|
||||
t = Math.atan2(uy, ux);
|
||||
|
||||
// draw segment
|
||||
context.moveTo(x1 - rx, y1 - ry);
|
||||
context.lineTo(x2 - ux * r2, y2 - uy * r2);
|
||||
context.arc(x2, y2, r2, t - Math.PI, t);
|
||||
context.lineTo(x1 + rx, y1 + ry);
|
||||
context.arc(x1, y1, r1, t, t + Math.PI);
|
||||
} else {
|
||||
context.arc(x2, y2, r2, 0, Tau);
|
||||
}
|
||||
context.closePath();
|
||||
} else {
|
||||
ready = 1;
|
||||
}
|
||||
x1 = x2;
|
||||
y1 = y2;
|
||||
r1 = r2;
|
||||
}
|
||||
|
||||
function trail(data) {
|
||||
var i,
|
||||
n = data.length,
|
||||
d,
|
||||
defined0 = false,
|
||||
buffer;
|
||||
|
||||
if (context == null) context = buffer = path();
|
||||
|
||||
for (i = 0; i <= n; ++i) {
|
||||
if (!(i < n && defined(d = data[i], i, data)) === defined0) {
|
||||
if (defined0 = !defined0) ready = 0;
|
||||
}
|
||||
if (defined0) point(+x(d, i, data), +y(d, i, data), +size(d, i, data));
|
||||
}
|
||||
|
||||
if (buffer) {
|
||||
context = null;
|
||||
return buffer + '' || null;
|
||||
}
|
||||
}
|
||||
|
||||
trail.x = function(_) {
|
||||
if (arguments.length) {
|
||||
x = _;
|
||||
return trail;
|
||||
} else {
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
trail.y = function(_) {
|
||||
if (arguments.length) {
|
||||
y = _;
|
||||
return trail;
|
||||
} else {
|
||||
return y;
|
||||
}
|
||||
};
|
||||
|
||||
trail.size = function(_) {
|
||||
if (arguments.length) {
|
||||
size = _;
|
||||
return trail;
|
||||
} else {
|
||||
return size;
|
||||
}
|
||||
};
|
||||
|
||||
trail.defined = function(_) {
|
||||
if (arguments.length) {
|
||||
defined = _;
|
||||
return trail;
|
||||
} else {
|
||||
return defined;
|
||||
}
|
||||
};
|
||||
|
||||
trail.context = function(_) {
|
||||
if (arguments.length) {
|
||||
if (_ == null) {
|
||||
context = null;
|
||||
} else {
|
||||
context = _;
|
||||
}
|
||||
return trail;
|
||||
} else {
|
||||
return context;
|
||||
}
|
||||
};
|
||||
|
||||
return trail;
|
||||
}
|
||||
167
node_modules/vega-scenegraph/src/util/aria.js
generated
vendored
Normal file
167
node_modules/vega-scenegraph/src/util/aria.js
generated
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
import {domainCaption, isDiscrete} from 'vega-scale';
|
||||
import {array, peek, toSet} from 'vega-util';
|
||||
|
||||
const ARIA_HIDDEN = 'aria-hidden';
|
||||
const ARIA_LABEL = 'aria-label';
|
||||
const ARIA_ROLE = 'role';
|
||||
const ARIA_ROLEDESCRIPTION = 'aria-roledescription';
|
||||
const GRAPHICS_OBJECT = 'graphics-object';
|
||||
const GRAPHICS_SYMBOL = 'graphics-symbol';
|
||||
|
||||
const bundle = (role, roledesc, label) => ({
|
||||
[ARIA_ROLE]: role,
|
||||
[ARIA_ROLEDESCRIPTION]: roledesc,
|
||||
[ARIA_LABEL]: label || undefined
|
||||
});
|
||||
|
||||
// these roles are covered by related roles
|
||||
// we can ignore them, no need to generate attributes
|
||||
const AriaIgnore = toSet([
|
||||
'axis-domain',
|
||||
'axis-grid',
|
||||
'axis-label',
|
||||
'axis-tick',
|
||||
'axis-title',
|
||||
'legend-band',
|
||||
'legend-entry',
|
||||
'legend-gradient',
|
||||
'legend-label',
|
||||
'legend-title',
|
||||
'legend-symbol',
|
||||
'title'
|
||||
]);
|
||||
|
||||
// aria attribute generators for guide roles
|
||||
const AriaGuides = {
|
||||
'axis': {desc: 'axis', caption: axisCaption},
|
||||
'legend': {desc: 'legend', caption: legendCaption},
|
||||
'title-text': {
|
||||
desc: 'title',
|
||||
caption: item => `Title text '${titleCaption(item)}'`
|
||||
},
|
||||
'title-subtitle': {
|
||||
desc: 'subtitle',
|
||||
caption: item => `Subtitle text '${titleCaption(item)}'`
|
||||
}
|
||||
};
|
||||
|
||||
// aria properties generated for mark item encoding channels
|
||||
export const AriaEncode = {
|
||||
ariaRole: ARIA_ROLE,
|
||||
ariaRoleDescription: ARIA_ROLEDESCRIPTION,
|
||||
description: ARIA_LABEL
|
||||
};
|
||||
|
||||
export function ariaItemAttributes(emit, item) {
|
||||
const hide = item.aria === false;
|
||||
emit(ARIA_HIDDEN, hide || undefined);
|
||||
|
||||
if (hide || item.description == null) {
|
||||
for (const prop in AriaEncode) {
|
||||
emit(AriaEncode[prop], undefined);
|
||||
}
|
||||
} else {
|
||||
const type = item.mark.marktype;
|
||||
emit(
|
||||
ARIA_LABEL,
|
||||
item.description
|
||||
);
|
||||
emit(
|
||||
ARIA_ROLE,
|
||||
item.ariaRole || (type === 'group' ? GRAPHICS_OBJECT : GRAPHICS_SYMBOL)
|
||||
);
|
||||
emit(
|
||||
ARIA_ROLEDESCRIPTION,
|
||||
item.ariaRoleDescription || `${type} mark`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function ariaMarkAttributes(mark) {
|
||||
return mark.aria === false ? { [ARIA_HIDDEN]: true }
|
||||
: AriaIgnore[mark.role] ? null
|
||||
: AriaGuides[mark.role] ? ariaGuide(mark, AriaGuides[mark.role])
|
||||
: ariaMark(mark);
|
||||
}
|
||||
|
||||
function ariaMark(mark) {
|
||||
const type = mark.marktype;
|
||||
const recurse = (
|
||||
type === 'group' ||
|
||||
type === 'text' ||
|
||||
mark.items.some(_ => _.description != null && _.aria !== false)
|
||||
);
|
||||
return bundle(
|
||||
recurse ? GRAPHICS_OBJECT : GRAPHICS_SYMBOL,
|
||||
`${type} mark container`,
|
||||
mark.description
|
||||
);
|
||||
}
|
||||
|
||||
function ariaGuide(mark, opt) {
|
||||
try {
|
||||
const item = mark.items[0],
|
||||
caption = opt.caption || (() => '');
|
||||
return bundle(
|
||||
opt.role || GRAPHICS_SYMBOL,
|
||||
opt.desc,
|
||||
item.description || caption(item)
|
||||
);
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function titleCaption(item) {
|
||||
return array(item.text).join(' ');
|
||||
}
|
||||
|
||||
function axisCaption(item) {
|
||||
const datum = item.datum,
|
||||
orient = item.orient,
|
||||
title = datum.title ? extractTitle(item) : null,
|
||||
ctx = item.context,
|
||||
scale = ctx.scales[datum.scale].value,
|
||||
locale = ctx.dataflow.locale(),
|
||||
type = scale.type,
|
||||
xy = (orient === 'left' || orient === 'right') ? 'Y' : 'X';
|
||||
|
||||
return `${xy}-axis`
|
||||
+ (title ? ` titled '${title}'` : '')
|
||||
+ ` for a ${isDiscrete(type) ? 'discrete' : type} scale`
|
||||
+ ` with ${domainCaption(locale, scale, item)}`;
|
||||
}
|
||||
|
||||
function legendCaption(item) {
|
||||
const datum = item.datum,
|
||||
title = datum.title ? extractTitle(item) : null,
|
||||
type = `${datum.type || ''} legend`.trim(),
|
||||
scales = datum.scales,
|
||||
props = Object.keys(scales),
|
||||
ctx = item.context,
|
||||
scale = ctx.scales[scales[props[0]]].value,
|
||||
locale = ctx.dataflow.locale();
|
||||
|
||||
return capitalize(type)
|
||||
+ (title ? ` titled '${title}'` : '')
|
||||
+ ` for ${channelCaption(props)}`
|
||||
+ ` with ${domainCaption(locale, scale, item)}`;
|
||||
}
|
||||
|
||||
function extractTitle(item) {
|
||||
try {
|
||||
return array(peek(item.items).items[0].text).join(' ');
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function channelCaption(props) {
|
||||
props = props.map(p => p + (p === 'fill' || p === 'stroke' ? ' color' : ''));
|
||||
return props.length < 2 ? props[0]
|
||||
: props.slice(0, -1).join(', ') + ' and ' + peek(props);
|
||||
}
|
||||
|
||||
function capitalize(s) {
|
||||
return s.length ? s[0].toUpperCase() + s.slice(1) : s;
|
||||
}
|
||||
3
node_modules/vega-scenegraph/src/util/canvas/blend.js
generated
vendored
Normal file
3
node_modules/vega-scenegraph/src/util/canvas/blend.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function(context, item) {
|
||||
context.globalCompositeOperation = item.blend || 'source-over';
|
||||
}
|
||||
24
node_modules/vega-scenegraph/src/util/canvas/clip.js
generated
vendored
Normal file
24
node_modules/vega-scenegraph/src/util/canvas/clip.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
import {hasCornerRadius, rectangle} from '../../path/shapes';
|
||||
import {isFunction} from 'vega-util';
|
||||
|
||||
export default function(context, scene) {
|
||||
var clip = scene.clip;
|
||||
|
||||
context.save();
|
||||
|
||||
if (isFunction(clip)) {
|
||||
context.beginPath();
|
||||
clip(context);
|
||||
context.clip();
|
||||
} else {
|
||||
clipGroup(context, scene.group);
|
||||
}
|
||||
}
|
||||
|
||||
export function clipGroup(context, group) {
|
||||
context.beginPath();
|
||||
hasCornerRadius(group)
|
||||
? rectangle(context, group, 0, 0)
|
||||
: context.rect(0, 0, group.width || 0, group.height || 0);
|
||||
context.clip();
|
||||
}
|
||||
8
node_modules/vega-scenegraph/src/util/canvas/color.js
generated
vendored
Normal file
8
node_modules/vega-scenegraph/src/util/canvas/color.js
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import {isGradient} from '../../Gradient';
|
||||
import gradient from './gradient';
|
||||
|
||||
export default function(context, item, value) {
|
||||
return isGradient(value)
|
||||
? gradient(context, value, item.bounds)
|
||||
: value;
|
||||
}
|
||||
5
node_modules/vega-scenegraph/src/util/canvas/context.js
generated
vendored
Normal file
5
node_modules/vega-scenegraph/src/util/canvas/context.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
import {canvas} from 'vega-canvas';
|
||||
|
||||
export var context = (context = canvas(1,1))
|
||||
? context.getContext('2d')
|
||||
: null;
|
||||
39
node_modules/vega-scenegraph/src/util/canvas/draw.js
generated
vendored
Normal file
39
node_modules/vega-scenegraph/src/util/canvas/draw.js
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
import blend from './blend';
|
||||
import fill from './fill';
|
||||
import stroke from './stroke';
|
||||
import {visit} from '../visit';
|
||||
|
||||
export function drawAll(path) {
|
||||
return function(context, scene, bounds) {
|
||||
visit(scene, function(item) {
|
||||
if (!bounds || bounds.intersects(item.bounds)) {
|
||||
drawPath(path, context, item, item);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function drawOne(path) {
|
||||
return function(context, scene, bounds) {
|
||||
if (scene.items.length && (!bounds || bounds.intersects(scene.bounds))) {
|
||||
drawPath(path, context, scene.items[0], scene.items);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function drawPath(path, context, item, items) {
|
||||
var opacity = item.opacity == null ? 1 : item.opacity;
|
||||
if (opacity === 0) return;
|
||||
|
||||
if (path(context, items)) return;
|
||||
|
||||
blend(context, item);
|
||||
|
||||
if (item.fill && fill(context, item, opacity)) {
|
||||
context.fill();
|
||||
}
|
||||
|
||||
if (item.stroke && stroke(context, item, opacity)) {
|
||||
context.stroke();
|
||||
}
|
||||
}
|
||||
12
node_modules/vega-scenegraph/src/util/canvas/fill.js
generated
vendored
Normal file
12
node_modules/vega-scenegraph/src/util/canvas/fill.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import color from './color';
|
||||
|
||||
export default function(context, item, opacity) {
|
||||
opacity *= (item.fillOpacity==null ? 1 : item.fillOpacity);
|
||||
if (opacity > 0) {
|
||||
context.globalAlpha = opacity;
|
||||
context.fillStyle = color(context, item, item.fill);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
59
node_modules/vega-scenegraph/src/util/canvas/gradient.js
generated
vendored
Normal file
59
node_modules/vega-scenegraph/src/util/canvas/gradient.js
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
import value from '../value';
|
||||
import {canvas} from 'vega-canvas';
|
||||
|
||||
function addStops(gradient, stops) {
|
||||
const n = stops.length;
|
||||
for (let i=0; i<n; ++i) {
|
||||
gradient.addColorStop(stops[i].offset, stops[i].color);
|
||||
}
|
||||
return gradient;
|
||||
}
|
||||
|
||||
export default function(context, spec, bounds) {
|
||||
const w = bounds.width(),
|
||||
h = bounds.height();
|
||||
let gradient;
|
||||
|
||||
|
||||
if (spec.gradient === 'radial') {
|
||||
gradient = context.createRadialGradient(
|
||||
bounds.x1 + value(spec.x1, 0.5) * w,
|
||||
bounds.y1 + value(spec.y1, 0.5) * h,
|
||||
Math.max(w, h) * value(spec.r1, 0),
|
||||
bounds.x1 + value(spec.x2, 0.5) * w,
|
||||
bounds.y1 + value(spec.y2, 0.5) * h,
|
||||
Math.max(w, h) * value(spec.r2, 0.5)
|
||||
);
|
||||
} else { // linear gradient
|
||||
const x1 = value(spec.x1, 0),
|
||||
y1 = value(spec.y1, 0),
|
||||
x2 = value(spec.x2, 1),
|
||||
y2 = value(spec.y2, 0);
|
||||
|
||||
if (x1 === x2 || y1 === y2 || w === h) {
|
||||
// axis aligned: use normal gradient
|
||||
gradient = context.createLinearGradient(
|
||||
bounds.x1 + x1 * w,
|
||||
bounds.y1 + y1 * h,
|
||||
bounds.x1 + x2 * w,
|
||||
bounds.y1 + y2 * h
|
||||
);
|
||||
} else {
|
||||
// not axis aligned: render gradient into a pattern (#2365)
|
||||
// this allows us to use normalized bounding box coordinates
|
||||
const image = canvas(Math.ceil(w), Math.ceil(h)),
|
||||
ictx = image.getContext('2d');
|
||||
|
||||
ictx.scale(w, h);
|
||||
ictx.fillStyle = addStops(
|
||||
ictx.createLinearGradient(x1, y1, x2, y2),
|
||||
spec.stops
|
||||
);
|
||||
ictx.fillRect(0, 0, w, h);
|
||||
|
||||
return context.createPattern(image, 'no-repeat');
|
||||
}
|
||||
}
|
||||
|
||||
return addStops(gradient, spec.stops);
|
||||
}
|
||||
4
node_modules/vega-scenegraph/src/util/canvas/image.js
generated
vendored
Normal file
4
node_modules/vega-scenegraph/src/util/canvas/image.js
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import {Canvas} from './canvas';
|
||||
|
||||
export default typeof Image !== 'undefined' ? Image
|
||||
: (Canvas && Canvas.Image || null);
|
||||
42
node_modules/vega-scenegraph/src/util/canvas/pick.js
generated
vendored
Normal file
42
node_modules/vega-scenegraph/src/util/canvas/pick.js
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
import {pickVisit} from '../visit';
|
||||
import {truthy} from 'vega-util';
|
||||
|
||||
export function pick(test) {
|
||||
test = test || truthy;
|
||||
|
||||
return function(context, scene, x, y, gx, gy) {
|
||||
x *= context.pixelRatio;
|
||||
y *= context.pixelRatio;
|
||||
|
||||
return pickVisit(scene, function(item) {
|
||||
var b = item.bounds;
|
||||
// first hit test against bounding box
|
||||
if ((b && !b.contains(gx, gy)) || !b) return;
|
||||
// if in bounding box, perform more careful test
|
||||
if (test(context, item, x, y, gx, gy)) return item;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function hitPath(path, filled) {
|
||||
return function(context, o, x, y) {
|
||||
var item = Array.isArray(o) ? o[0] : o,
|
||||
fill = (filled == null) ? item.fill : filled,
|
||||
stroke = item.stroke && context.isPointInStroke, lw, lc;
|
||||
|
||||
if (stroke) {
|
||||
lw = item.strokeWidth;
|
||||
lc = item.strokeCap;
|
||||
context.lineWidth = lw != null ? lw : 1;
|
||||
context.lineCap = lc != null ? lc : 'butt';
|
||||
}
|
||||
|
||||
return path(context, o) ? false :
|
||||
(fill && context.isPointInPath(x, y)) ||
|
||||
(stroke && context.isPointInStroke(x, y));
|
||||
};
|
||||
}
|
||||
|
||||
export function pickPath(path) {
|
||||
return pick(hitPath(path));
|
||||
}
|
||||
34
node_modules/vega-scenegraph/src/util/canvas/resize.js
generated
vendored
Normal file
34
node_modules/vega-scenegraph/src/util/canvas/resize.js
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
function devicePixelRatio() {
|
||||
return typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1;
|
||||
}
|
||||
|
||||
var pixelRatio = devicePixelRatio();
|
||||
|
||||
export default function(canvas, width, height, origin, scaleFactor, opt) {
|
||||
const inDOM = typeof HTMLElement !== 'undefined'
|
||||
&& canvas instanceof HTMLElement
|
||||
&& canvas.parentNode != null,
|
||||
context = canvas.getContext('2d'),
|
||||
ratio = inDOM ? pixelRatio : scaleFactor;
|
||||
|
||||
canvas.width = width * ratio;
|
||||
canvas.height = height * ratio;
|
||||
|
||||
for (const key in opt) {
|
||||
context[key] = opt[key];
|
||||
}
|
||||
|
||||
if (inDOM && ratio !== 1) {
|
||||
canvas.style.width = width + 'px';
|
||||
canvas.style.height = height + 'px';
|
||||
}
|
||||
|
||||
context.pixelRatio = ratio;
|
||||
context.setTransform(
|
||||
ratio, 0, 0, ratio,
|
||||
ratio * origin[0],
|
||||
ratio * origin[1]
|
||||
);
|
||||
|
||||
return canvas;
|
||||
}
|
||||
28
node_modules/vega-scenegraph/src/util/canvas/stroke.js
generated
vendored
Normal file
28
node_modules/vega-scenegraph/src/util/canvas/stroke.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
import color from './color';
|
||||
|
||||
var Empty = [];
|
||||
|
||||
export default function(context, item, opacity) {
|
||||
var lw = (lw = item.strokeWidth) != null ? lw : 1;
|
||||
|
||||
if (lw <= 0) return false;
|
||||
|
||||
opacity *= (item.strokeOpacity==null ? 1 : item.strokeOpacity);
|
||||
if (opacity > 0) {
|
||||
context.globalAlpha = opacity;
|
||||
context.strokeStyle = color(context, item, item.stroke);
|
||||
|
||||
context.lineWidth = lw;
|
||||
context.lineCap = item.strokeCap || 'butt';
|
||||
context.lineJoin = item.strokeJoin || 'miter';
|
||||
context.miterLimit = item.strokeMiterLimit || 10;
|
||||
|
||||
if (context.setLineDash) {
|
||||
context.setLineDash(item.strokeDash || Empty);
|
||||
context.lineDashOffset = item.strokeDashOffset || 0;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
5
node_modules/vega-scenegraph/src/util/constants.js
generated
vendored
Normal file
5
node_modules/vega-scenegraph/src/util/constants.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
export const DegToRad = Math.PI / 180;
|
||||
export const Epsilon = 1e-14;
|
||||
export const HalfPi = Math.PI / 2;
|
||||
export const Tau = Math.PI * 2;
|
||||
export const HalfSqrt3 = Math.sqrt(3) / 2;
|
||||
45
node_modules/vega-scenegraph/src/util/dom.js
generated
vendored
Normal file
45
node_modules/vega-scenegraph/src/util/dom.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
// create a new DOM element
|
||||
export function domCreate(doc, tag, ns) {
|
||||
if (!doc && typeof document !== 'undefined' && document.createElement) {
|
||||
doc = document;
|
||||
}
|
||||
return doc
|
||||
? (ns ? doc.createElementNS(ns, tag) : doc.createElement(tag))
|
||||
: null;
|
||||
}
|
||||
|
||||
// find first child element with matching tag
|
||||
export function domFind(el, tag) {
|
||||
tag = tag.toLowerCase();
|
||||
var nodes = el.childNodes, i = 0, n = nodes.length;
|
||||
for (; i<n; ++i) if (nodes[i].tagName.toLowerCase() === tag) {
|
||||
return nodes[i];
|
||||
}
|
||||
}
|
||||
|
||||
// retrieve child element at given index
|
||||
// create & insert if doesn't exist or if tags do not match
|
||||
export function domChild(el, index, tag, ns) {
|
||||
var a = el.childNodes[index], b;
|
||||
if (!a || a.tagName.toLowerCase() !== tag.toLowerCase()) {
|
||||
b = a || null;
|
||||
a = domCreate(el.ownerDocument, tag, ns);
|
||||
el.insertBefore(a, b);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
// remove all child elements at or above the given index
|
||||
export function domClear(el, index) {
|
||||
var nodes = el.childNodes,
|
||||
curr = nodes.length;
|
||||
while (curr > index) el.removeChild(nodes[--curr]);
|
||||
return el;
|
||||
}
|
||||
|
||||
// generate css class name for mark
|
||||
export function cssClass(mark) {
|
||||
return 'mark-' + mark.marktype
|
||||
+ (mark.role ? ' role-' + mark.role : '')
|
||||
+ (mark.name ? ' ' + mark.name : '');
|
||||
}
|
||||
40
node_modules/vega-scenegraph/src/util/equal.js
generated
vendored
Normal file
40
node_modules/vega-scenegraph/src/util/equal.js
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
import pathParse from '../path/parse';
|
||||
import {isNumber, isObject} from 'vega-util';
|
||||
|
||||
var TOLERANCE = 1e-9;
|
||||
|
||||
export function sceneEqual(a, b, key) {
|
||||
return (a === b) ? true
|
||||
: (key === 'path') ? pathEqual(a, b)
|
||||
: (a instanceof Date && b instanceof Date) ? +a === +b
|
||||
: (isNumber(a) && isNumber(b)) ? Math.abs(a - b) <= TOLERANCE
|
||||
: (!a || !b || !isObject(a) && !isObject(b)) ? a == b
|
||||
: (a == null || b == null) ? false
|
||||
: objectEqual(a, b);
|
||||
}
|
||||
|
||||
export function pathEqual(a, b) {
|
||||
return sceneEqual(pathParse(a), pathParse(b));
|
||||
}
|
||||
|
||||
function objectEqual(a, b) {
|
||||
var ka = Object.keys(a),
|
||||
kb = Object.keys(b),
|
||||
key, i;
|
||||
|
||||
if (ka.length !== kb.length) return false;
|
||||
|
||||
ka.sort();
|
||||
kb.sort();
|
||||
|
||||
for (i = ka.length - 1; i >= 0; i--) {
|
||||
if (ka[i] != kb[i]) return false;
|
||||
}
|
||||
|
||||
for (i = ka.length - 1; i >= 0; i--) {
|
||||
key = ka[i];
|
||||
if (!sceneEqual(a[key], b[key], key)) return false;
|
||||
}
|
||||
|
||||
return typeof a === typeof b;
|
||||
}
|
||||
45
node_modules/vega-scenegraph/src/util/events.js
generated
vendored
Normal file
45
node_modules/vega-scenegraph/src/util/events.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
export const KeyDownEvent = 'keydown';
|
||||
export const KeyPressEvent = 'keypress';
|
||||
export const KeyUpEvent = 'keyup';
|
||||
export const DragEnterEvent = 'dragenter';
|
||||
export const DragLeaveEvent = 'dragleave';
|
||||
export const DragOverEvent = 'dragover';
|
||||
export const MouseDownEvent = 'mousedown';
|
||||
export const MouseUpEvent = 'mouseup';
|
||||
export const MouseMoveEvent = 'mousemove';
|
||||
export const MouseOutEvent = 'mouseout';
|
||||
export const MouseOverEvent = 'mouseover';
|
||||
export const ClickEvent = 'click';
|
||||
export const DoubleClickEvent = 'dblclick';
|
||||
export const WheelEvent = 'wheel';
|
||||
export const MouseWheelEvent = 'mousewheel';
|
||||
export const TouchStartEvent = 'touchstart';
|
||||
export const TouchMoveEvent = 'touchmove';
|
||||
export const TouchEndEvent = 'touchend';
|
||||
|
||||
export const Events = [
|
||||
KeyDownEvent,
|
||||
KeyPressEvent,
|
||||
KeyUpEvent,
|
||||
DragEnterEvent,
|
||||
DragLeaveEvent,
|
||||
DragOverEvent,
|
||||
MouseDownEvent,
|
||||
MouseUpEvent,
|
||||
MouseMoveEvent,
|
||||
MouseOutEvent,
|
||||
MouseOverEvent,
|
||||
ClickEvent,
|
||||
DoubleClickEvent,
|
||||
WheelEvent,
|
||||
MouseWheelEvent,
|
||||
TouchStartEvent,
|
||||
TouchMoveEvent,
|
||||
TouchEndEvent
|
||||
];
|
||||
|
||||
export const TooltipShowEvent = MouseMoveEvent;
|
||||
|
||||
export const TooltipHideEvent = MouseOutEvent;
|
||||
|
||||
export const HrefEvent = ClickEvent;
|
||||
80
node_modules/vega-scenegraph/src/util/intersect.js
generated
vendored
Normal file
80
node_modules/vega-scenegraph/src/util/intersect.js
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
import {context} from './canvas/context';
|
||||
import Bounds from '../Bounds';
|
||||
|
||||
const b = new Bounds();
|
||||
|
||||
export function intersectPath(draw) {
|
||||
return function(item, brush) {
|
||||
// rely on (inaccurate) bounds intersection if no context
|
||||
if (!context) return true;
|
||||
|
||||
// add path to offscreen graphics context
|
||||
draw(context, item);
|
||||
|
||||
// get bounds intersection region
|
||||
b.clear().union(item.bounds).intersect(brush).round();
|
||||
const {x1, y1, x2, y2} = b;
|
||||
|
||||
// iterate over intersection region
|
||||
// perform fine grained inclusion test
|
||||
for (let y = y1; y <= y2; ++y) {
|
||||
for (let x = x1; x <= x2; ++x) {
|
||||
if (context.isPointInPath(x, y)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// false if no hits in intersection region
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
export function intersectPoint(item, box) {
|
||||
return box.contains(item.x || 0, item.y || 0);
|
||||
}
|
||||
|
||||
export function intersectRect(item, box) {
|
||||
const x = item.x || 0,
|
||||
y = item.y || 0,
|
||||
w = item.width || 0,
|
||||
h = item.height || 0;
|
||||
return box.intersects(b.set(x, y, x + w, y + h));
|
||||
}
|
||||
|
||||
export function intersectRule(item, box) {
|
||||
const x = item.x || 0,
|
||||
y = item.y || 0,
|
||||
x2 = item.x2 != null ? item.x2 : x,
|
||||
y2 = item.y2 != null ? item.y2 : y;
|
||||
return intersectBoxLine(box, x, y, x2, y2);
|
||||
}
|
||||
|
||||
export function intersectBoxLine(box, x, y, u, v) {
|
||||
const {x1, y1, x2, y2} = box,
|
||||
dx = u - x,
|
||||
dy = v - y;
|
||||
|
||||
let t0 = 0, t1 = 1, p, q, r, e;
|
||||
|
||||
for (e=0; e<4; ++e) {
|
||||
if (e === 0) { p = -dx; q = -(x1 - x); }
|
||||
if (e === 1) { p = dx; q = (x2 - x); }
|
||||
if (e === 2) { p = -dy; q = -(y1 - y); }
|
||||
if (e === 3) { p = dy; q = (y2 - y); }
|
||||
|
||||
if (Math.abs(p) < 1e-10 && q < 0) return false;
|
||||
|
||||
r = q / p;
|
||||
|
||||
if (p < 0) {
|
||||
if (r > t1) return false;
|
||||
else if (r > t0) t0 = r;
|
||||
} else if (p > 0) {
|
||||
if (r < t0) return false;
|
||||
else if (r < t1) t1 = r;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
47
node_modules/vega-scenegraph/src/util/pickPath.js
generated
vendored
Normal file
47
node_modules/vega-scenegraph/src/util/pickPath.js
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
export function pickArea(a, p) {
|
||||
var v = a[0].orient === 'horizontal' ? p[1] : p[0],
|
||||
z = a[0].orient === 'horizontal' ? 'y' : 'x',
|
||||
i = a.length,
|
||||
min = +Infinity, hit, d;
|
||||
|
||||
while (--i >= 0) {
|
||||
if (a[i].defined === false) continue;
|
||||
d = Math.abs(a[i][z] - v);
|
||||
if (d < min) {
|
||||
min = d;
|
||||
hit = a[i];
|
||||
}
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
export function pickLine(a, p) {
|
||||
var t = Math.pow(a[0].strokeWidth || 1, 2),
|
||||
i = a.length, dx, dy, dd;
|
||||
|
||||
while (--i >= 0) {
|
||||
if (a[i].defined === false) continue;
|
||||
dx = a[i].x - p[0];
|
||||
dy = a[i].y - p[1];
|
||||
dd = dx * dx + dy * dy;
|
||||
if (dd < t) return a[i];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function pickTrail(a, p) {
|
||||
var i = a.length, dx, dy, dd;
|
||||
|
||||
while (--i >= 0) {
|
||||
if (a[i].defined === false) continue;
|
||||
dx = a[i].x - p[0];
|
||||
dy = a[i].y - p[1];
|
||||
dd = dx * dx + dy * dy;
|
||||
dx = a[i].size || 1;
|
||||
if (dd < dx*dx) return a[i];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
7
node_modules/vega-scenegraph/src/util/point.js
generated
vendored
Normal file
7
node_modules/vega-scenegraph/src/util/point.js
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function(event, el) {
|
||||
var rect = el.getBoundingClientRect();
|
||||
return [
|
||||
event.clientX - rect.left - (el.clientLeft || 0),
|
||||
event.clientY - rect.top - (el.clientTop || 0)
|
||||
];
|
||||
}
|
||||
20
node_modules/vega-scenegraph/src/util/resolveItem.js
generated
vendored
Normal file
20
node_modules/vega-scenegraph/src/util/resolveItem.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import marks from '../marks/index';
|
||||
import point from './point';
|
||||
|
||||
export default function(item, event, el, origin) {
|
||||
var mark = item && item.mark,
|
||||
mdef, p;
|
||||
|
||||
if (mark && (mdef = marks[mark.marktype]).tip) {
|
||||
p = point(event, el);
|
||||
p[0] -= origin[0];
|
||||
p[1] -= origin[1];
|
||||
while (item = item.mark.group) {
|
||||
p[0] -= item.x || 0;
|
||||
p[1] -= item.y || 0;
|
||||
}
|
||||
item = mdef.tip(mark.items, p);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
50
node_modules/vega-scenegraph/src/util/serialize.js
generated
vendored
Normal file
50
node_modules/vega-scenegraph/src/util/serialize.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
import boundMark from '../bound/boundMark';
|
||||
|
||||
var keys = [
|
||||
'marktype', 'name', 'role', 'interactive', 'clip', 'items', 'zindex',
|
||||
'x', 'y', 'width', 'height', 'align', 'baseline', // layout
|
||||
'fill', 'fillOpacity', 'opacity', 'blend', // fill
|
||||
'stroke', 'strokeOpacity', 'strokeWidth', 'strokeCap', // stroke
|
||||
'strokeDash', 'strokeDashOffset', // stroke dash
|
||||
'strokeForeground', 'strokeOffset', // group
|
||||
'startAngle', 'endAngle', 'innerRadius', 'outerRadius', // arc
|
||||
'cornerRadius', 'padAngle', // arc, rect
|
||||
'cornerRadiusTopLeft', 'cornerRadiusTopRight', // rect, group
|
||||
'cornerRadiusBottomLeft', 'cornerRadiusBottomRight',
|
||||
'interpolate', 'tension', 'orient', 'defined', // area, line
|
||||
'url', 'aspect', 'smooth', // image
|
||||
'path', 'scaleX', 'scaleY', // path
|
||||
'x2', 'y2', // rule
|
||||
'size', 'shape', // symbol
|
||||
'text', 'angle', 'theta', 'radius', 'dir', 'dx', 'dy', // text
|
||||
'ellipsis', 'limit', 'lineBreak', 'lineHeight',
|
||||
'font', 'fontSize', 'fontWeight', 'fontStyle', 'fontVariant', // font
|
||||
'description', 'aria', 'ariaRole', 'ariaRoleDescription' // aria
|
||||
];
|
||||
|
||||
export function sceneToJSON(scene, indent) {
|
||||
return JSON.stringify(scene, keys, indent);
|
||||
}
|
||||
|
||||
export function sceneFromJSON(json) {
|
||||
var scene = (typeof json === 'string' ? JSON.parse(json) : json);
|
||||
return initialize(scene);
|
||||
}
|
||||
|
||||
function initialize(scene) {
|
||||
var type = scene.marktype,
|
||||
items = scene.items,
|
||||
parent, i, n;
|
||||
|
||||
if (items) {
|
||||
for (i=0, n=items.length; i<n; ++i) {
|
||||
parent = type ? 'mark' : 'group';
|
||||
items[i][parent] = scene;
|
||||
if (items[i].zindex) items[i][parent].zdirty = true;
|
||||
if ('group' === (type || parent)) initialize(items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (type) boundMark(scene);
|
||||
return scene;
|
||||
}
|
||||
26
node_modules/vega-scenegraph/src/util/svg/clip.js
generated
vendored
Normal file
26
node_modules/vega-scenegraph/src/util/svg/clip.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
import {hasCornerRadius, rectangle} from '../../path/shapes';
|
||||
import {isFunction} from 'vega-util';
|
||||
|
||||
var clip_id = 1;
|
||||
|
||||
export function resetSVGClipId() {
|
||||
clip_id = 1;
|
||||
}
|
||||
|
||||
export default function(renderer, item, size) {
|
||||
var clip = item.clip,
|
||||
defs = renderer._defs,
|
||||
id = item.clip_id || (item.clip_id = 'clip' + clip_id++),
|
||||
c = defs.clipping[id] || (defs.clipping[id] = {id: id});
|
||||
|
||||
if (isFunction(clip)) {
|
||||
c.path = clip(null);
|
||||
} else if (hasCornerRadius(size)) {
|
||||
c.path = rectangle(null, size, 0, 0);
|
||||
} else {
|
||||
c.width = size.width || 0;
|
||||
c.height = size.height || 0;
|
||||
}
|
||||
|
||||
return 'url(#' + id + ')';
|
||||
}
|
||||
5
node_modules/vega-scenegraph/src/util/svg/metadata.js
generated
vendored
Normal file
5
node_modules/vega-scenegraph/src/util/svg/metadata.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
export default {
|
||||
'version': '1.1',
|
||||
'xmlns': 'http://www.w3.org/2000/svg',
|
||||
'xmlns:xlink': 'http://www.w3.org/1999/xlink'
|
||||
};
|
||||
20
node_modules/vega-scenegraph/src/util/svg/styles.js
generated
vendored
Normal file
20
node_modules/vega-scenegraph/src/util/svg/styles.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
export const styles = {
|
||||
fill: 'fill',
|
||||
fillOpacity: 'fill-opacity',
|
||||
stroke: 'stroke',
|
||||
strokeOpacity: 'stroke-opacity',
|
||||
strokeWidth: 'stroke-width',
|
||||
strokeCap: 'stroke-linecap',
|
||||
strokeJoin: 'stroke-linejoin',
|
||||
strokeDash: 'stroke-dasharray',
|
||||
strokeDashOffset: 'stroke-dashoffset',
|
||||
strokeMiterLimit: 'stroke-miterlimit',
|
||||
opacity: 'opacity',
|
||||
blend: 'mix-blend-mode'
|
||||
};
|
||||
|
||||
// ensure miter limit default is consistent with canvas (#2498)
|
||||
export const rootAttributes = {
|
||||
'fill': 'none',
|
||||
'stroke-miterlimit': 10
|
||||
};
|
||||
21
node_modules/vega-scenegraph/src/util/svg/transform.js
generated
vendored
Normal file
21
node_modules/vega-scenegraph/src/util/svg/transform.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
export function translate(x, y) {
|
||||
return 'translate(' + x + ',' + y + ')';
|
||||
}
|
||||
|
||||
export function rotate(a) {
|
||||
return 'rotate(' + a + ')';
|
||||
}
|
||||
|
||||
export function scale(scaleX, scaleY){
|
||||
return 'scale('+ scaleX + ',' + scaleY+')';
|
||||
}
|
||||
|
||||
export function translateItem(item) {
|
||||
return translate(item.x || 0, item.y || 0);
|
||||
}
|
||||
|
||||
export function transformItem(item) {
|
||||
return translate(item.x || 0, item.y || 0)
|
||||
+ (item.angle ? ' ' + rotate(item.angle) : '')
|
||||
+ (item.scaleX || item.scaleY ? ' ' + scale(item.scaleX || 1, item.scaleY || 1) : '');
|
||||
}
|
||||
31
node_modules/vega-scenegraph/src/util/tags.js
generated
vendored
Normal file
31
node_modules/vega-scenegraph/src/util/tags.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
const attrText = val => (val + '')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"');
|
||||
|
||||
/**
|
||||
* Generate string for an opening xml tag.
|
||||
* @param tag the name of the xml tag
|
||||
* @param attr hash of attribute name-value pairs to include
|
||||
* @param raw additional raw string to include in tag markup
|
||||
*/
|
||||
export function openTag(tag, attr, raw) {
|
||||
var s = '<' + tag, key, val;
|
||||
if (attr) {
|
||||
for (key in attr) {
|
||||
val = attr[key];
|
||||
if (val != null) {
|
||||
s += ' ' + key + '="' + attrText(val) + '"';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (raw) s += ' ' + raw;
|
||||
return s + '>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate string for closing xml tag.
|
||||
* @param tag the name of the xml tag
|
||||
*/
|
||||
export function closeTag(tag) {
|
||||
return '</' + tag + '>';
|
||||
}
|
||||
149
node_modules/vega-scenegraph/src/util/text.js
generated
vendored
Normal file
149
node_modules/vega-scenegraph/src/util/text.js
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
import {context} from './canvas/context';
|
||||
import {isArray, lruCache} from 'vega-util';
|
||||
|
||||
// memoize text width measurement
|
||||
const widthCache = lruCache();
|
||||
|
||||
export var textMetrics = {
|
||||
height: fontSize,
|
||||
measureWidth: measureWidth,
|
||||
estimateWidth: estimateWidth,
|
||||
width: estimateWidth,
|
||||
canvas: useCanvas
|
||||
};
|
||||
|
||||
useCanvas(true);
|
||||
|
||||
function useCanvas(use) {
|
||||
textMetrics.width = (use && context) ? measureWidth : estimateWidth;
|
||||
}
|
||||
|
||||
// make dumb, simple estimate if no canvas is available
|
||||
function estimateWidth(item, text) {
|
||||
return _estimateWidth(textValue(item, text), fontSize(item));
|
||||
}
|
||||
|
||||
function _estimateWidth(text, currentFontHeight) {
|
||||
return ~~(0.8 * text.length * currentFontHeight);
|
||||
}
|
||||
|
||||
// measure text width if canvas is available
|
||||
function measureWidth(item, text) {
|
||||
return fontSize(item) <= 0 || !(text = textValue(item, text)) ? 0
|
||||
: _measureWidth(text, font(item));
|
||||
}
|
||||
|
||||
function _measureWidth(text, currentFont) {
|
||||
const key = `(${currentFont}) ${text}`;
|
||||
let width = widthCache.get(key);
|
||||
if (width === undefined) {
|
||||
context.font = currentFont;
|
||||
width = context.measureText(text).width;
|
||||
widthCache.set(key, width);
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
export function fontSize(item) {
|
||||
return item.fontSize != null ? (+item.fontSize || 0) : 11;
|
||||
}
|
||||
|
||||
export function lineHeight(item) {
|
||||
return item.lineHeight != null ? item.lineHeight : (fontSize(item) + 2);
|
||||
}
|
||||
|
||||
function lineArray(_) {
|
||||
return isArray(_) ? _.length > 1 ? _ : _[0] : _;
|
||||
}
|
||||
|
||||
export function textLines(item) {
|
||||
return lineArray(
|
||||
item.lineBreak && item.text && !isArray(item.text)
|
||||
? item.text.split(item.lineBreak)
|
||||
: item.text
|
||||
);
|
||||
}
|
||||
|
||||
export function multiLineOffset(item) {
|
||||
const tl = textLines(item);
|
||||
return (isArray(tl) ? (tl.length - 1) : 0) * lineHeight(item);
|
||||
}
|
||||
|
||||
export function textValue(item, line) {
|
||||
const text = line == null ? '' : (line + '').trim();
|
||||
return item.limit > 0 && text.length ? truncate(item, text) : text;
|
||||
}
|
||||
|
||||
function widthGetter(item) {
|
||||
if (textMetrics.width === measureWidth) {
|
||||
// we are using canvas
|
||||
const currentFont = font(item);
|
||||
return text => _measureWidth(text, currentFont);
|
||||
} else {
|
||||
// we are relying on estimates
|
||||
const currentFontHeight = fontSize(item);
|
||||
return text => _estimateWidth(text, currentFontHeight);
|
||||
}
|
||||
}
|
||||
|
||||
function truncate(item, text) {
|
||||
var limit = +item.limit,
|
||||
width = widthGetter(item);
|
||||
|
||||
if (width(text) < limit) return text;
|
||||
|
||||
var ellipsis = item.ellipsis || '\u2026',
|
||||
rtl = item.dir === 'rtl',
|
||||
lo = 0,
|
||||
hi = text.length, mid;
|
||||
|
||||
limit -= width(ellipsis);
|
||||
|
||||
if (rtl) {
|
||||
while (lo < hi) {
|
||||
mid = (lo + hi >>> 1);
|
||||
if (width(text.slice(mid)) > limit) lo = mid + 1;
|
||||
else hi = mid;
|
||||
}
|
||||
return ellipsis + text.slice(lo);
|
||||
} else {
|
||||
while (lo < hi) {
|
||||
mid = 1 + (lo + hi >>> 1);
|
||||
if (width(text.slice(0, mid)) < limit) lo = mid;
|
||||
else hi = mid - 1;
|
||||
}
|
||||
return text.slice(0, lo) + ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
export function fontFamily(item, quote) {
|
||||
var font = item.font;
|
||||
return (quote && font
|
||||
? String(font).replace(/"/g, '\'')
|
||||
: font) || 'sans-serif';
|
||||
}
|
||||
|
||||
export function font(item, quote) {
|
||||
return '' +
|
||||
(item.fontStyle ? item.fontStyle + ' ' : '') +
|
||||
(item.fontVariant ? item.fontVariant + ' ' : '') +
|
||||
(item.fontWeight ? item.fontWeight + ' ' : '') +
|
||||
fontSize(item) + 'px ' +
|
||||
fontFamily(item, quote);
|
||||
}
|
||||
|
||||
export function offset(item) {
|
||||
// perform our own font baseline calculation
|
||||
// why? not all browsers support SVG 1.1 'alignment-baseline' :(
|
||||
// this also ensures consistent layout across renderers
|
||||
var baseline = item.baseline,
|
||||
h = fontSize(item);
|
||||
|
||||
return Math.round(
|
||||
baseline === 'top' ? 0.79 * h :
|
||||
baseline === 'middle' ? 0.30 * h :
|
||||
baseline === 'bottom' ? -0.21 * h :
|
||||
baseline === 'line-top' ? 0.29 * h + 0.5 * lineHeight(item) :
|
||||
baseline === 'line-bottom' ? 0.29 * h - 0.5 * lineHeight(item) : 0
|
||||
);
|
||||
}
|
||||
3
node_modules/vega-scenegraph/src/util/value.js
generated
vendored
Normal file
3
node_modules/vega-scenegraph/src/util/value.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function(value, dflt) {
|
||||
return value == null ? dflt : value;
|
||||
}
|
||||
59
node_modules/vega-scenegraph/src/util/visit.js
generated
vendored
Normal file
59
node_modules/vega-scenegraph/src/util/visit.js
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
function compare(a, b) {
|
||||
return a.zindex - b.zindex || a.index - b.index;
|
||||
}
|
||||
|
||||
export function zorder(scene) {
|
||||
if (!scene.zdirty) return scene.zitems;
|
||||
|
||||
var items = scene.items,
|
||||
output = [], item, i, n;
|
||||
|
||||
for (i=0, n=items.length; i<n; ++i) {
|
||||
item = items[i];
|
||||
item.index = i;
|
||||
if (item.zindex) output.push(item);
|
||||
}
|
||||
|
||||
scene.zdirty = false;
|
||||
return scene.zitems = output.sort(compare);
|
||||
}
|
||||
|
||||
export function visit(scene, visitor) {
|
||||
var items = scene.items, i, n;
|
||||
if (!items || !items.length) return;
|
||||
|
||||
var zitems = zorder(scene);
|
||||
|
||||
if (zitems && zitems.length) {
|
||||
for (i=0, n=items.length; i<n; ++i) {
|
||||
if (!items[i].zindex) visitor(items[i]);
|
||||
}
|
||||
items = zitems;
|
||||
}
|
||||
|
||||
for (i=0, n=items.length; i<n; ++i) {
|
||||
visitor(items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
export function pickVisit(scene, visitor) {
|
||||
var items = scene.items, hit, i;
|
||||
if (!items || !items.length) return null;
|
||||
|
||||
var zitems = zorder(scene);
|
||||
if (zitems && zitems.length) items = zitems;
|
||||
|
||||
for (i=items.length; --i >= 0;) {
|
||||
if (hit = visitor(items[i])) return hit;
|
||||
}
|
||||
|
||||
if (items === zitems) {
|
||||
for (items=scene.items, i=items.length; --i >= 0;) {
|
||||
if (!items[i].zindex) {
|
||||
if (hit = visitor(items[i])) return hit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user