https://provence-alpes-cotedazur.com/app/dist/crt-paca/addons/wood…/Core/Renderer/SVG/SVGRenderer.js
vendor: 26,164 bytes, lines 1-726
1/* * 2 * 3 * (c) 2010-2024 Torstein Honsi 4 * 5 * License: www.highcharts.com/license 6 * 7 * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! 8 * 9 * */ 10'use strict'; 11import AST from '../HTML/AST.js'; 12import D from '../../Defaults.js'; 13const { defaultOptions } = D; 14import Color from '../../Color/Color.js'; 15import H from '../../Globals.js'; 16const { charts, deg2rad, doc, isFirefox, isMS, isWebKit, noop, SVG_NS, symbolSizes, win } = H; 17import RendererRegistry from '../RendererRegistry.js'; 18import SVGElement from './SVGElement.js'; 19import SVGLabel from './SVGLabel.js'; 20import Symbols from './Symbols.js'; 21import TextBuilder from './TextBuilder.js'; 22import U from '../../Utilities.js'; 23const { addEvent, attr, createElement, crisp, css, defined, destroyObjectProperties, extend, isArray, isNumber, isObject, isString, merge, pick, pInt, replaceNested, uniqueKey } = U; 24/* * 25 * 26 * Variables 27 * 28 * */ 29let hasInternalReferenceBug; 30/* * 31 * 32 * Class 33 * 34 * */ 35/* eslint-disable no-invalid-this, valid-jsdoc */ 36/** 37 * Allows direct access to the Highcharts rendering layer in order to draw 38 * primitive shapes like circles, rectangles, paths or text directly on a chart, 39 * or independent from any chart. The SVGRenderer represents a wrapper object 40 * for SVG in modern browsers. 41 * 42 * An existing chart's renderer can be accessed through {@link Chart.renderer}. 43 * The renderer can also be used completely decoupled from a chart. 44 * 45 * See [How to use the SVG Renderer]( 46 * https://www.highcharts.com/docs/advanced-chart-features/renderer) for a 47 * comprehensive tutorial. 48 * 49 * @sample highcharts/members/renderer-on-chart 50 * Annotating a chart programmatically. 51 * @sample highcharts/members/renderer-basic 52 * Independent SVG drawing. 53 * 54 * @example 55 * // Use directly without a chart object. 56 * let renderer = new Highcharts.Renderer(parentNode, 600, 400); 57 * 58 * @class 59 * @name Highcharts.SVGRenderer 60 * 61 * @param {Highcharts.HTMLDOMElement} container 62 * Where to put the SVG in the web page. 63 * 64 * @param {number} width 65 * The width of the SVG. 66 * 67 * @param {number} height 68 * The height of the SVG. 69 * 70 * @param {Highcharts.CSSObject} [style] 71 * The box style, if not in styleMode 72 * 73 * @param {boolean} [forExport=false] 74 * Whether the rendered content is intended for export. 75 * 76 * @param {boolean} [allowHTML=true] 77 * Whether the renderer is allowed to include HTML text, which will be 78 * projected on top of the SVG. 79 * 80 * @param {boolean} [styledMode=false] 81 * Whether the renderer belongs to a chart that is in styled mode. 82 * If it does, it will avoid setting presentational attributes in 83 * some cases, but not when set explicitly through `.attr` and `.css` 84 * etc. 85 */ 86class SVGRenderer { 87 /** 88 * The root `svg` node of the renderer. 89 * 90 * @name Highcharts.SVGRenderer#box 91 * @type {Highcharts.SVGDOMElement} 92 */ 93 /** 94 * The wrapper for the root `svg` node of the renderer. 95 * 96 * @name Highcharts.SVGRenderer#boxWrapper 97 * @type {Highcharts.SVGElement} 98 */ 99 /** 100 * A pointer to the `defs` node of the root SVG. 101 * 102 * @name Highcharts.SVGRenderer#defs 103 * @type {Highcharts.SVGElement} 104 */ 105 /** 106 * Whether the rendered content is intended for export. 107 * 108 * @name Highcharts.SVGRenderer#forExport 109 * @type {boolean | undefined} 110 */ 111 /** 112 * Page url used for internal references. 113 * 114 * @private 115 * @name Highcharts.SVGRenderer#url 116 * @type {string} 117 */ 118 /** 119 * Initialize the SVGRenderer. Overridable initializer function that takes 120 * the same parameters as the constructor. 121 * 122 * @function Highcharts.SVGRenderer#init 123 * 124 * @param {Highcharts.HTMLDOMElement} container 125 * Where to put the SVG in the web page. 126 * 127 * @param {number} width 128 * The width of the SVG. 129 * 130 * @param {number} height 131 * The height of the SVG. 132 * 133 * @param {Highcharts.CSSObject} [style] 134 * The box style, if not in styleMode 135 * 136 * @param {boolean} [forExport=false] 137 * Whether the rendered content is intended for export. 138 * 139 * @param {boolean} [allowHTML=true] 140 * Whether the renderer is allowed to include HTML text, which will be 141 * projected on top of the SVG. 142 * 143 * @param {boolean} [styledMode=false] 144 * Whether the renderer belongs to a chart that is in styled mode. If it 145 * does, it will avoid setting presentational attributes in some cases, but 146 * not when set explicitly through `.attr` and `.css` etc. 147 */ 148 constructor(container, width, height, style, forExport, allowHTML, styledMode) { 149 const renderer = this, boxWrapper = renderer 150 .createElement('svg') 151 .attr({ 152 version: '1.1', 153 'class': 'highcharts-root' 154 }), element = boxWrapper.element; 155 if (!styledMode) { 156 boxWrapper.css(this.getStyle(style || {})); 157 } 158 container.appendChild(element); 159 // Always use ltr on the container, otherwise text-anchor will be 160 // flipped and text appear outside labels, buttons, tooltip etc (#3482) 161 attr(container, 'dir', 'ltr'); 162 // For browsers other than IE, add the namespace attribute (#1978) 163 if (container.innerHTML.indexOf('xmlns') === -1) { 164 attr(element, 'xmlns', this.SVG_NS); 165 } 166 this.box = element; 167 this.boxWrapper = boxWrapper; 168 this.alignedObjects = []; 169 this.url = this.getReferenceURL(); 170 // Add description 171 const desc = this.createElement('desc').add(); 172 desc.element.appendChild(doc.createTextNode('Created with @product.name@ @product.version@')); 173 this.defs = this.createElement('defs').add(); 174 this.allowHTML = allowHTML; 175 this.forExport = forExport; 176 this.styledMode = styledMode; 177 this.gradients = {}; // Object where gradient SvgElements are stored 178 this.cache = {}; // Cache for numerical bounding boxes 179 this.cacheKeys = []; 180 this.imgCount = 0; 181 this.rootFontSize = boxWrapper.getStyle('font-size'); 182 renderer.setSize(width, height, false); 183 // Issue 110 workaround: 184 // In Firefox, if a div is positioned by percentage, its pixel position 185 // may land between pixels. The container itself doesn't display this, 186 // but an SVG element inside this container will be drawn at subpixel 187 // precision. In order to draw sharp lines, this must be compensated 188 // for. This doesn't seem to work inside iframes though (like in 189 // jsFiddle). 190 let subPixelFix, rect; 191 if (isFirefox && container.getBoundingClientRect) { 192 subPixelFix = function () { 193 css(container, { left: 0, top: 0 }); 194 rect = container.getBoundingClientRect(); 195 css(container, { 196 left: (Math.ceil(rect.left) - rect.left) + 'px', 197 top: (Math.ceil(rect.top) - rect.top) + 'px' 198 }); 199 }; 200 // Run the fix now 201 subPixelFix(); 202 // Run it on resize 203 renderer.unSubPixelFix = addEvent(win, 'resize', subPixelFix); 204 } 205 } 206 /* * 207 * 208 * Functions 209 * 210 * */ 211 /** 212 * General method for adding a definition to the SVG `defs` tag. Can be used 213 * for gradients, fills, filters etc. Styled mode only. A hook for adding 214 * general definitions to the SVG's defs tag. Definitions can be referenced 215 * from the CSS by its `id`. Read more in 216 * [gradients, shadows and patterns](https://www.highcharts.com/docs/chart-design-and-style/gradients-shadows-and-patterns). 217 * Styled mode only. 218 * 219 * @function Highcharts.SVGRenderer#definition 220 * 221 * @param {Highcharts.ASTNode} def 222 * A serialized form of an SVG definition, including children. 223 * 224 * @return {Highcharts.SVGElement} 225 * The inserted node. 226 */ 227 definition(def) { 228 const ast = new AST([def]); 229 return ast.addToDOM(this.defs.element); 230 } 231 /** 232 * Get the prefix needed for internal URL references to work in certain 233 * cases. Some older browser versions had a bug where internal url 234 * references in SVG attributes, on the form `url(#some-id)`, would fail if 235 * a base tag was present in the page. There were also issues with 236 * `history.pushState` related to this prefix. 237 * 238 * Related issues: #24, #672, #1070, #5244. 239 * 240 * The affected browsers are: 241 * - Chrome <= 53 (May 2018) 242 * - Firefox <= 51 (January 2017) 243 * - Safari/Mac <= 12.1 (2018 or 2019) 244 * - Safari/iOS <= 13 245 * 246 * @todo Remove this hack when time has passed. All the affected browsers 247 * are evergreens, so it is increasingly unlikely that users are affected by 248 * the bug. 249 * 250 * @return {string} 251 * The prefix to use. An empty string for modern browsers. 252 */ 253 getReferenceURL() { 254 if ((isFirefox || isWebKit) && 255 doc.getElementsByTagName('base').length) { 256 // Detect if a clip path is taking effect by performing a hit test 257 // outside the clipped area. If the hit element is the rectangle 258 // that was supposed to be clipped, the bug is present. This only 259 // has to be performed once per page load, so we store the result 260 // locally in the module. 261 if (!defined(hasInternalReferenceBug)) { 262 const id = uniqueKey(); 263 const ast = new AST([{ 264 tagName: 'svg', 265 attributes: { 266 width: 8, 267 height: 8 268 }, 269 children: [{ 270 tagName: 'defs', 271 children: [{ 272 tagName: 'clipPath', 273 attributes: { 274 id 275 }, 276 children: [{ 277 tagName: 'rect', 278 attributes: { 279 width: 4, 280 height: 4 281 } 282 }] 283 }] 284 }, { 285 tagName: 'rect', 286 attributes: { 287 id: 'hitme', 288 width: 8, 289 height: 8, 290 'clip-path': `url(#${id})`, 291 fill: 'rgba(0,0,0,0.001)' 292 } 293 }] 294 }]); 295 const svg = ast.addToDOM(doc.body); 296 css(svg, { 297 position: 'fixed', 298 top: 0, 299 left: 0, 300 zIndex: 9e5 301 }); 302 const hitElement = doc.elementFromPoint(6, 6); 303 hasInternalReferenceBug = (hitElement && hitElement.id) === 'hitme'; 304 doc.body.removeChild(svg); 305 } 306 if (hasInternalReferenceBug) { 307 // Scan alert #[72]: Loop for nested patterns 308 return replaceNested(win.location.href.split('#')[0], // Remove hash 309 [/<[^>]*>/g, ''], // Wing cut HTML 310 [/([\('\)])/g, '\\$1'], // Escape parantheses and quotes 311 [/ /g, '%20'] // Replace spaces (needed for Safari only) 312 ); 313 } 314 } 315 return ''; 316 } 317 /** 318 * Get the global style setting for the renderer. 319 * 320 * @private 321 * @function Highcharts.SVGRenderer#getStyle 322 * 323 * @param {Highcharts.CSSObject} style 324 * Style settings. 325 * 326 * @return {Highcharts.CSSObject} 327 * The style settings mixed with defaults. 328 */ 329 getStyle(style) { 330 this.style = extend({ 331 fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", ' + 332 'Roboto, Helvetica, Arial, "Apple Color Emoji", ' + 333 '"Segoe UI Emoji", "Segoe UI Symbol", sans-serif', 334 fontSize: '1rem' 335 }, style); 336 return this.style; 337 } 338 /** 339 * Apply the global style on the renderer, mixed with the default styles. 340 * 341 * @function Highcharts.SVGRenderer#setStyle 342 * 343 * @param {Highcharts.CSSObject} style 344 * CSS to apply. 345 */ 346 setStyle(style) { 347 this.boxWrapper.css(this.getStyle(style)); 348 } 349 /** 350 * Detect whether the renderer is hidden. This happens when one of the 351 * parent elements has `display: none`. Used internally to detect when we 352 * need to render preliminarily in another div to get the text bounding 353 * boxes right. 354 * 355 * @function Highcharts.SVGRenderer#isHidden 356 * 357 * @return {boolean} 358 * True if it is hidden. 359 */ 360 isHidden() { 361 return !this.boxWrapper.getBBox().width; 362 } 363 /** 364 * Destroys the renderer and its allocated members. 365 * 366 * @function Highcharts.SVGRenderer#destroy 367 * 368 * @return {null} 369 * Pass through value. 370 */ 371 destroy() { 372 const renderer = this, rendererDefs = renderer.defs; 373 renderer.box = null; 374 renderer.boxWrapper = renderer.boxWrapper.destroy(); 375 // Call destroy on all gradient elements 376 destroyObjectProperties(renderer.gradients || {}); 377 renderer.gradients = null; 378 renderer.defs = rendererDefs.destroy(); 379 // Remove sub pixel fix handler (#982) 380 if (renderer.unSubPixelFix) { 381 renderer.unSubPixelFix(); 382 } 383 renderer.alignedObjects = null; 384 return null; 385 } 386 /** 387 * Create a wrapper for an SVG element. Serves as a factory for 388 * {@link SVGElement}, but this function is itself mostly called from 389 * primitive factories like {@link SVGRenderer#path}, {@link 390 * SVGRenderer#rect} or {@link SVGRenderer#text}. 391 * 392 * @function Highcharts.SVGRenderer#createElement 393 * 394 * @param {string} nodeName 395 * The node name, for example `rect`, `g` etc. 396 * 397 * @return {Highcharts.SVGElement} 398 * The generated SVGElement. 399 */ 400 createElement(nodeName) { 401 return new this.Element(this, nodeName); 402 } 403 /** 404 * Get converted radial gradient attributes according to the radial 405 * reference. Used internally from the {@link SVGElement#colorGradient} 406 * function. 407 * 408 * @private 409 * @function Highcharts.SVGRenderer#getRadialAttr 410 */ 411 getRadialAttr(radialReference, gradAttr) { 412 return { 413 cx: (radialReference[0] - radialReference[2] / 2) + 414 (gradAttr.cx || 0) * radialReference[2], 415 cy: (radialReference[1] - radialReference[2] / 2) + 416 (gradAttr.cy || 0) * radialReference[2], 417 r: (gradAttr.r || 0) * radialReference[2] 418 }; 419 } 420 /** 421 * Create a drop shadow definition and return its id 422 * 423 * @private 424 * @function Highcharts.SVGRenderer#shadowDefinition 425 * 426 * @param {boolean|Highcharts.ShadowOptionsObject} [shadowOptions] The 427 * shadow options. If `true`, the default options are applied 428 */ 429 shadowDefinition(shadowOptions) { 430 const id = [ 431 `highcharts-drop-shadow-${this.chartIndex}`, 432 ...Object.keys(shadowOptions) 433 .map((key) => `${key}-${shadowOptions[key]}`) 434 ].join('-').toLowerCase().replace(/[^a-z\d\-]/g, ''), options = merge({ 435 color: '#000000', 436 offsetX: 1, 437 offsetY: 1, 438 opacity: 0.15, 439 width: 5 440 }, shadowOptions); 441 if (!this.defs.element.querySelector(`#${id}`)) { 442 this.definition({ 443 tagName: 'filter', 444 attributes: { 445 id, 446 filterUnits: options.filterUnits 447 }, 448 children: this.getShadowFilterContent(options) 449 }); 450 } 451 return id; 452 } 453 /** 454 * Get shadow filter content. 455 * NOTE! Overridden in es5 module for IE11 compatibility. 456 * 457 * @private 458 * @function Highcharts.SVGRenderer#getShadowFilterContent 459 * 460 * @param {ShadowOptionsObject} options 461 * The shadow options. 462 * @return {Array<AST.Node>} 463 * The shadow filter content. 464 */ 465 getShadowFilterContent(options) { 466 return [{ 467 tagName: 'feDropShadow', 468 attributes: { 469 dx: options.offsetX, 470 dy: options.offsetY, 471 'flood-color': options.color, 472 // Tuned and modified to keep a preserve compatibility 473 // with the old settings 474 'flood-opacity': Math.min(options.opacity * 5, 1), 475 stdDeviation: options.width / 2 476 } 477 }]; 478 } 479 /** 480 * Parse a simple HTML string into SVG tspans. Called internally when text 481 * is set on an SVGElement. The function supports a subset of HTML tags, CSS 482 * text features like `width`, `text-overflow`, `white-space`, and also 483 * attributes like `href` and `style`. 484 * 485 * @private 486 * @function Highcharts.SVGRenderer#buildText 487 * 488 * @param {Highcharts.SVGElement} wrapper 489 * The parent SVGElement. 490 */ 491 buildText(wrapper) { 492 new TextBuilder(wrapper).buildSVG(); 493 } 494 /** 495 * Returns white for dark colors and black for bright colors, based on W3C's 496 * definition of [Relative luminance]( 497 * https://www.w3.org/WAI/GL/wiki/Relative_luminance). 498 * 499 * @function Highcharts.SVGRenderer#getContrast 500 * 501 * @param {Highcharts.ColorString} color 502 * The color to get the contrast for. 503 * 504 * @return {Highcharts.ColorString} 505 * The contrast color, either `#000000` or `#FFFFFF`. 506 */ 507 getContrast(color) { 508 // #6216, #17273 509 const rgba = Color.parse(color).rgba 510 .map((b8) => { 511 const c = b8 / 255; 512 return c <= 0.03928 ? 513 c / 12.92 : 514 Math.pow((c + 0.055) / 1.055, 2.4); 515 }); 516 // Relative luminance 517 const l = 0.2126 * rgba[0] + 0.7152 * rgba[1] + 0.0722 * rgba[2]; 518 // Use white or black based on which provides more contrast 519 return 1.05 / (l + 0.05) > (l + 0.05) / 0.05 ? '#FFFFFF' : '#000000'; 520 } 521 /** 522 * Create a button with preset states. Styles for the button can either be 523 * set as arguments, or a general theme for all buttons can be set by the 524 * `global.buttonTheme` option. 525 * 526 * @function Highcharts.SVGRenderer#button 527 * 528 * @param {string} text 529 * The text or HTML to draw. 530 * 531 * @param {number} x 532 * The x position of the button's left side. 533 * 534 * @param {number} y 535 * The y position of the button's top side. 536 * 537 * @param {Highcharts.EventCallbackFunction<Highcharts.SVGElement>} callback 538 * The function to execute on button click or touch. 539 * 540 * @param {Highcharts.SVGAttributes} [theme] 541 * SVG attributes for the normal state. 542 * 543 * @param {Highcharts.SVGAttributes} [hoverState] 544 * SVG attributes for the hover state. 545 * 546 * @param {Highcharts.SVGAttributes} [selectState] 547 * SVG attributes for the pressed state. 548 * 549 * @param {Highcharts.SVGAttributes} [disabledState] 550 * SVG attributes for the disabled state. 551 * 552 * @param {Highcharts.SymbolKeyValue} [shape=rect] 553 * The shape type. 554 * 555 * @param {boolean} [useHTML=false] 556 * Whether to use HTML to render the label. 557 * 558 * @return {Highcharts.SVGElement} 559 * The button element. 560 */ 561 button(text, x, y, callback, theme = {}, hoverState, selectState, disabledState, shape, useHTML) { 562 const label = this.label(text, x, y, shape, void 0, void 0, useHTML, void 0, 'button'), styledMode = this.styledMode, args = arguments; 563 let curState = 0; 564 theme = merge(defaultOptions.global.buttonTheme, theme); 565 // @todo Consider moving this to a lower level, like .attr 566 if (styledMode) { 567 delete theme.fill; 568 delete theme.stroke; 569 delete theme['stroke-width']; 570 } 571 const states = theme.states || {}, normalStyle = theme.style || {}; 572 delete theme.states; 573 delete theme.style; 574 // Presentational 575 const stateAttribs = [ 576 AST.filterUserAttributes(theme) 577 ], 578 // The string type is a mistake, it is just for compliance with 579 // SVGAttribute and is not used in button theme. 580 stateStyles = [normalStyle]; 581 if (!styledMode) { 582 ['hover', 'select', 'disabled'].forEach((stateName, i) => { 583 stateAttribs.push(merge(stateAttribs[0], AST.filterUserAttributes(args[i + 5] || states[stateName] || {}))); 584 stateStyles.push(stateAttribs[i + 1].style); 585 delete stateAttribs[i + 1].style; 586 }); 587 } 588 // Add the events. IE9 and IE10 need mouseover and mouseout to function 589 // (#667). 590 addEvent(label.element, isMS ? 'mouseover' : 'mouseenter', function () { 591 if (curState !== 3) { 592 label.setState(1); 593 } 594 }); 595 addEvent(label.element, isMS ? 'mouseout' : 'mouseleave', function () { 596 if (curState !== 3) { 597 label.setState(curState); 598 } 599 }); 600 label.setState = (state = 0) => { 601 // Hover state is temporary, don't record it 602 if (state !== 1) { 603 label.state = curState = state; 604 } 605 // Update visuals 606 label 607 .removeClass(/highcharts-button-(normal|hover|pressed|disabled)/) 608 .addClass('highcharts-button-' + 609 ['normal', 'hover', 'pressed', 'disabled'][state]); 610 if (!styledMode) { 611 label.attr(stateAttribs[state]); 612 const css = stateStyles[state]; 613 if (isObject(css)) { 614 label.css(css); 615 } 616 } 617 }; 618 label.attr(stateAttribs[0]); 619 // Presentational attributes 620 if (!styledMode) { 621 label.css(extend({ cursor: 'default' }, normalStyle)); 622 // HTML labels don't need to handle pointer events because click and 623 // mouseenter/mouseleave is bound to the underlying <g> element. 624 // Should this be reconsidered, we need more complex logic to share 625 // events between the <g> and its <div> counterpart, and avoid 626 // triggering mouseenter/mouseleave when hovering from one to the 627 // other (#17440). 628 if (useHTML) { 629 label.text.css({ pointerEvents: 'none' }); 630 } 631 } 632 return label 633 .on('touchstart', (e) => e.stopPropagation()) 634 .on('click', function (e) { 635 if (curState !== 3) { 636 callback.call(label, e); 637 } 638 }); 639 } 640 /** 641 * Make a straight line crisper by not spilling out to neighbour pixels. 642 * 643 * @function Highcharts.SVGRenderer#crispLine 644 * 645 * @param {Highcharts.SVGPathArray} points 646 * The original points on the format `[['M', 0, 0], ['L', 100, 0]]`. 647 * 648 * @param {number} width 649 * The width of the line. 650 * 651 * @return {Highcharts.SVGPathArray} 652 * The original points array, but modified to render crisply. 653 */ 654 crispLine(points, width) { 655 const [start, end] = points; 656 // Normalize to a crisp line 657 if (defined(start[1]) && start[1] === end[1]) { 658 start[1] = end[1] = crisp(start[1], width); 659 } 660 if (defined(start[2]) && start[2] === end[2]) { 661 start[2] = end[2] = crisp(start[2], width); 662 } 663 return points; 664 } 665 /** 666 * Draw a path, wraps the SVG `path` element. 667 * 668 * @sample highcharts/members/renderer-path-on-chart/ 669 * Draw a path in a chart 670 * @sample highcharts/members/renderer-path/ 671 * Draw a path independent from a chart 672 * 673 * @example 674 * let path = renderer.path(['M', 10, 10, 'L', 30, 30, 'z']) 675 * .attr({ stroke: '#ff00ff' }) 676 * .add(); 677 * 678 * @function Highcharts.SVGRenderer#path 679 * 680 * @param {Highcharts.SVGPathArray} [path] 681 * An SVG path definition in array form. 682 * 683 * @return {Highcharts.SVGElement} 684 * The generated wrapper element. 685 * 686 */ /** 687 * Draw a path, wraps the SVG `path` element. 688 * 689 * @function Highcharts.SVGRenderer#path 690 * 691 * @param {Highcharts.SVGAttributes} [attribs] 692 * The initial attributes. 693 * 694 * @return {Highcharts.SVGElement} 695 * The generated wrapper element. 696 */ 697 path(path) { 698 const attribs = (this.styledMode ? {} : { 699 fill: 'none' 700 }); 701 if (isArray(path)) { 702 attribs.d = path; 703 } 704 else if (isObject(path)) { // Attributes 705 extend(attribs, path); 706 } 707 return this.createElement('path').attr(attribs); 708 } 709 /** 710 * Draw a circle, wraps the SVG `circle` element. 711 * 712 * @sample highcharts/members/renderer-circle/ 713 * Drawing a circle 714 * 715 * @function Highcharts.SVGRenderer#circle 716 * 717 * @param {number} [x] 718 * The center x position. 719 * 720 * @param {number} [y] 721 * The center y position. 722 * 723 * @param {number} [r] 724 * The radius. 725 * 726 * @return {Highcharts.SVGElement}
727 * The generated wrapper element. 728 */ /** 729 * Draw a circle, wraps the SVG `circle` element. 730 * 731 * @function Highcharts.SVGRenderer#circle 732 * 733 * @param {Highcharts.SVGAttributes} [attribs] 734 * The initial attributes. 735 * 736 * @return {Highcharts.SVGElement} 737 * The generated wrapper element. 738 */ 739 circle(x, y, r) { 740 const attribs = (isObject(x) ? 741 x : 742 typeof x === 'undefined' ? {} : { x: x, y: y, r: r }), wrapper = this.createElement('circle'); 743 // Setting x or y translates to cx and cy 744 wrapper.xSetter = wrapper.ySetter = function (value, key, element) { 745 element.setAttribute('c' + key, value); 746 }; 747 return wrapper.attr(attribs); 748 } 749 /** 750 * Draw and return an arc. 751 * 752 * @sample highcharts/members/renderer-arc/ 753 * Drawing an arc 754 * 755 * @function Highcharts.SVGRenderer#arc 756 * 757 * @param {number} [x=0] 758 * Center X position. 759 * 760 * @param {number} [y=0] 761 * Center Y position. 762 * 763 * @param {number} [r=0] 764 * The outer radius' of the arc. 765 * 766 * @param {number} [innerR=0] 767 * Inner radius like used in donut charts. 768 * 769 * @param {number} [start=0] 770 * The starting angle of the arc in radians, where 0 is to the right and 771 * `-Math.PI/2` is up. 772 * 773 * @param {number} [end=0] 774 * The ending angle of the arc in radians, where 0 is to the right and 775 * `-Math.PI/2` is up. 776 * 777 * @return {Highcharts.SVGElement} 778 * The generated wrapper element. 779 */ /** 780 * Draw and return an arc. Overloaded function that takes arguments object. 781 * 782 * @function Highcharts.SVGRenderer#arc 783 * 784 * @param {Highcharts.SVGAttributes} attribs 785 * Initial SVG attributes. 786 * 787 * @return {Highcharts.SVGElement} 788 * The generated wrapper element. 789 */ 790 arc(x, y, r, innerR, start, end) { 791 let options; 792 if (isObject(x)) { 793 options = x; 794 y = options.y; 795 r = options.r; 796 innerR = options.innerR; 797 start = options.start; 798 end = options.end; 799 x = options.x; 800 } 801 else { 802 options = { innerR, start, end }; 803 } 804 // Arcs are defined as symbols for the ability to set 805 // attributes in attr and animate 806 const arc = this.symbol('arc', x, y, r, r, options); 807 arc.r = r; // #959 808 return arc; 809 } 810 /** 811 * Draw and return a rectangle. 812 * 813 * @function Highcharts.SVGRenderer#rect 814 * 815 * @param {number} [x] 816 * Left position. 817 * 818 * @param {number} [y] 819 * Top position. 820 * 821 * @param {number} [width] 822 * Width of the rectangle. 823 * 824 * @param {number} [height] 825 * Height of the rectangle. 826 * 827 * @param {number} [r] 828 * Border corner radius. 829 * 830 * @param {number} [strokeWidth] 831 * A stroke width can be supplied to allow crisp drawing. 832 * 833 * @return {Highcharts.SVGElement} 834 * The generated wrapper element. 835 */ /** 836 * Draw and return a rectangle. 837 * 838 * @sample highcharts/members/renderer-rect-on-chart/ 839 * Draw a rectangle in a chart 840 * @sample highcharts/members/renderer-rect/ 841 * Draw a rectangle independent from a chart 842 * 843 * @function Highcharts.SVGRenderer#rect 844 * 845 * @param {Highcharts.SVGAttributes} [attributes] 846 * General SVG attributes for the rectangle. 847 * 848 * @return {Highcharts.SVGElement} 849 * The generated wrapper element. 850 */ 851 rect(x, y, width, height, r, strokeWidth) { 852 const attribs = (isObject(x) ? 853 x : 854 typeof x === 'undefined' ? 855 {} : 856 { 857 x, 858 y, 859 r, 860 width: Math.max(width || 0, 0), 861 height: Math.max(height || 0, 0) 862 }), wrapper = this.createElement('rect'); 863 if (!this.styledMode) { 864 if (typeof strokeWidth !== 'undefined') { 865 attribs['stroke-width'] = strokeWidth; 866 extend(attribs, wrapper.crisp(attribs)); 867 } 868 attribs.fill = 'none'; 869 } 870 wrapper.rSetter = function (value, _key, element) { 871 wrapper.r = value; 872 attr(element, { 873 rx: value, 874 ry: value 875 }); 876 }; 877 wrapper.rGetter = function () { 878 return wrapper.r || 0; 879 }; 880 return wrapper.attr(attribs); 881 } 882 /** 883 * Draw and return a rectangle with advanced corner rounding options. 884 * 885 * @function Highcharts.SVGRenderer#roundedRect 886 * 887 * @param {Highcharts.SVGAttributes} attribs 888 * Attributes 889 * @return {Highcharts.SVGElement}
vendor: 16,413 bytes, lines 890-1334
890 * The generated wrapper element. 891 */ 892 roundedRect(attribs) { 893 return this.symbol('roundedRect').attr(attribs); 894 } 895 /** 896 * Resize the {@link SVGRenderer#box} and re-align all aligned child 897 * elements. 898 * 899 * @sample highcharts/members/renderer-g/ 900 * Show and hide grouped objects 901 * 902 * @function Highcharts.SVGRenderer#setSize 903 * 904 * @param {number} width 905 * The new pixel width. 906 * 907 * @param {number} height 908 * The new pixel height. 909 * 910 * @param {boolean|Partial<Highcharts.AnimationOptionsObject>} [animate=true] 911 * Whether and how to animate. 912 */ 913 setSize(width, height, animate) { 914 const renderer = this; 915 renderer.width = width; 916 renderer.height = height; 917 renderer.boxWrapper.animate({ 918 width: width, 919 height: height 920 }, { 921 step: function () { 922 this.attr({ 923 viewBox: '0 0 ' + this.attr('width') + ' ' + 924 this.attr('height') 925 }); 926 }, 927 duration: pick(animate, true) ? void 0 : 0 928 }); 929 renderer.alignElements(); 930 } 931 /** 932 * Create and return an svg group element. Child 933 * {@link Highcharts.SVGElement} objects are added to the group by using the 934 * group as the first parameter in {@link Highcharts.SVGElement#add|add()}. 935 * 936 * @function Highcharts.SVGRenderer#g 937 * 938 * @param {string} [name] 939 * The group will be given a class name of `highcharts-{name}`. This 940 * can be used for styling and scripting. 941 * 942 * @return {Highcharts.SVGElement} 943 * The generated wrapper element. 944 */ 945 g(name) { 946 const elem = this.createElement('g'); 947 return name ? 948 elem.attr({ 'class': 'highcharts-' + name }) : 949 elem; 950 } 951 /** 952 * Display an image. 953 * 954 * @sample highcharts/members/renderer-image-on-chart/ 955 * Add an image in a chart 956 * @sample highcharts/members/renderer-image/ 957 * Add an image independent of a chart 958 * 959 * @function Highcharts.SVGRenderer#image 960 * 961 * @param {string} href 962 * The image source. 963 * 964 * @param {number} [x] 965 * The X position. 966 * 967 * @param {number} [y] 968 * The Y position. 969 * 970 * @param {number} [width] 971 * The image width. If omitted, it defaults to the image file width. 972 * 973 * @param {number} [height] 974 * The image height. If omitted it defaults to the image file 975 * height. 976 * 977 * @param {Function} [onload] 978 * Event handler for image load. 979 * 980 * @return {Highcharts.SVGElement} 981 * The generated wrapper element. 982 */ 983 image(href, x, y, width, height, onload) { 984 const attribs = { preserveAspectRatio: 'none' }; 985 // Optional properties (#11756) 986 if (isNumber(x)) { 987 attribs.x = x; 988 } 989 if (isNumber(y)) { 990 attribs.y = y; 991 } 992 if (isNumber(width)) { 993 attribs.width = width; 994 } 995 if (isNumber(height)) { 996 attribs.height = height; 997 } 998 const elemWrapper = this.createElement('image').attr(attribs), onDummyLoad = function (e) { 999 elemWrapper.attr({ href }); 1000 onload.call(elemWrapper, e); 1001 }; 1002 // Add load event if supplied 1003 if (onload) { 1004 // We have to use a dummy HTML image since IE support for SVG image 1005 // load events is very buggy. First set a transparent src, wait for 1006 // dummy to load, and then add the real src to the SVG image. 1007 elemWrapper.attr({ 1008 /* eslint-disable-next-line max-len */ 1009 href: 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==' 1010 }); 1011 const dummy = new win.Image(); 1012 addEvent(dummy, 'load', onDummyLoad); 1013 dummy.src = href; 1014 if (dummy.complete) { 1015 onDummyLoad({}); 1016 } 1017 } 1018 else { 1019 elemWrapper.attr({ href }); 1020 } 1021 return elemWrapper; 1022 } 1023 /** 1024 * Draw a symbol out of pre-defined shape paths from 1025 * {@link SVGRenderer#symbols}. 1026 * It is used in Highcharts for point makers, which cake a `symbol` option, 1027 * and label and button backgrounds like in the tooltip and stock flags. 1028 * 1029 * @function Highcharts.SVGRenderer#symbol 1030 * 1031 * @param {string} symbol 1032 * The symbol name. 1033 * 1034 * @param {number} [x] 1035 * The X coordinate for the top left position. 1036 * 1037 * @param {number} [y] 1038 * The Y coordinate for the top left position. 1039 * 1040 * @param {number} [width] 1041 * The pixel width. 1042 * 1043 * @param {number} [height] 1044 * The pixel height. 1045 * 1046 * @param {Highcharts.SymbolOptionsObject} [options] 1047 * Additional options, depending on the actual symbol drawn. 1048 * 1049 * @return {Highcharts.SVGElement} 1050 * SVG symbol. 1051 */ 1052 symbol(symbol, x, y, width, height, options) { 1053 const ren = this, imageRegex = /^url\((.*?)\)$/, isImage = imageRegex.test(symbol), sym = (!isImage && (this.symbols[symbol] ? symbol : 'circle')), 1054 // Get the symbol definition function 1055 symbolFn = (sym && this.symbols[sym]); 1056 let obj, path, imageSrc, centerImage; 1057 if (symbolFn) { 1058 // Check if there's a path defined for this symbol 1059 if (typeof x === 'number') { 1060 path = symbolFn.call(this.symbols, x || 0, y || 0, width || 0, height || 0, options); 1061 } 1062 obj = this.path(path); 1063 if (!ren.styledMode) { 1064 obj.attr('fill', 'none'); 1065 } 1066 // Expando properties for use in animate and attr 1067 extend(obj, { 1068 symbolName: (sym || void 0), 1069 x: x, 1070 y: y, 1071 width: width, 1072 height: height 1073 }); 1074 if (options) { 1075 extend(obj, options); 1076 } 1077 // Image symbols 1078 } 1079 else if (isImage) { 1080 imageSrc = symbol.match(imageRegex)[1]; 1081 // Create the image synchronously, add attribs async 1082 const img = obj = this.image(imageSrc); 1083 // The image width is not always the same as the symbol width. The 1084 // image may be centered within the symbol, as is the case when 1085 // image shapes are used as label backgrounds, for example in flags. 1086 img.imgwidth = pick(options && options.width, symbolSizes[imageSrc] && symbolSizes[imageSrc].width); 1087 img.imgheight = pick(options && options.height, symbolSizes[imageSrc] && symbolSizes[imageSrc].height); 1088 /** 1089 * Set the size and position 1090 */ 1091 centerImage = (obj) => obj.attr({ 1092 width: obj.width, 1093 height: obj.height 1094 }); 1095 /** 1096 * Width and height setters that take both the image's physical size 1097 * and the label size into consideration, and translates the image 1098 * to center within the label. 1099 */ 1100 ['width', 'height'].forEach((key) => { 1101 img[`${key}Setter`] = function (value, key) { 1102 this[key] = value; 1103 const { alignByTranslate, element, width, height, imgwidth, imgheight } = this, imgSize = key === 'width' ? imgwidth : imgheight; 1104 let scale = 1; 1105 // Scale and center the image within its container. The name 1106 // `backgroundSize` is taken from the CSS spec, but the 1107 // value `within` is made up. Other possible values in the 1108 // spec, `cover` and `contain`, can be implemented if 1109 // needed. 1110 if (options && 1111 options.backgroundSize === 'within' && 1112 width && 1113 height && 1114 imgwidth && 1115 imgheight) { 1116 scale = Math.min(width / imgwidth, height / imgheight); 1117 // Update both width and height to keep the ratio 1118 // correct (#17315) 1119 attr(element, { 1120 width: Math.round(imgwidth * scale), 1121 height: Math.round(imgheight * scale) 1122 }); 1123 } 1124 else if (element && imgSize) { 1125 element.setAttribute(key, imgSize); 1126 } 1127 if (!alignByTranslate && imgwidth && imgheight) { 1128 this.translate(((width || 0) - (imgwidth * scale)) / 2, ((height || 0) - (imgheight * scale)) / 2); 1129 } 1130 }; 1131 }); 1132 if (defined(x)) { 1133 img.attr({ 1134 x: x, 1135 y: y 1136 }); 1137 } 1138 img.isImg = true; 1139 img.symbolUrl = symbol; 1140 if (defined(img.imgwidth) && defined(img.imgheight)) { 1141 centerImage(img); 1142 } 1143 else { 1144 // Initialize image to be 0 size so export will still function 1145 // if there's no cached sizes. 1146 img.attr({ width: 0, height: 0 }); 1147 // Create a dummy JavaScript image to get the width and height. 1148 createElement('img', { 1149 onload: function () { 1150 const chart = charts[ren.chartIndex]; 1151 // Special case for SVGs on IE11, the width is not 1152 // accessible until the image is part of the DOM 1153 // (#2854). 1154 if (this.width === 0) { 1155 css(this, { 1156 position: 'absolute', 1157 top: '-999em' 1158 }); 1159 doc.body.appendChild(this); 1160 } 1161 // Center the image 1162 symbolSizes[imageSrc] = { 1163 width: this.width, 1164 height: this.height 1165 }; 1166 img.imgwidth = this.width; 1167 img.imgheight = this.height; 1168 if (img.element) { 1169 centerImage(img); 1170 } 1171 // Clean up after #2854 workaround. 1172 if (this.parentNode) { 1173 this.parentNode.removeChild(this); 1174 } 1175 // Fire the load event when all external images are 1176 // loaded 1177 ren.imgCount--; 1178 if (!ren.imgCount && chart && !chart.hasLoaded) { 1179 chart.onload(); 1180 } 1181 }, 1182 src: imageSrc 1183 }); 1184 this.imgCount++; 1185 } 1186 } 1187 return obj; 1188 } 1189 /** 1190 * Define a clipping rectangle. The clipping rectangle is later applied 1191 * to {@link SVGElement} objects through the {@link SVGElement#clip} 1192 * function. 1193 * 1194 * This function is deprecated as of v11.2. Instead, use a regular shape 1195 * (`rect`, `path` etc), and the `SVGElement.clipTo` function. 1196 * 1197 * @example 1198 * let circle = renderer.circle(100, 100, 100) 1199 * .attr({ fill: 'red' }) 1200 * .add(); 1201 * let clipRect = renderer.clipRect(100, 100, 100, 100); 1202 * 1203 * // Leave only the lower right quarter visible 1204 * circle.clip(clipRect); 1205 * 1206 * @deprecated 1207 * 1208 * @function Highcharts.SVGRenderer#clipRect 1209 * 1210 * @param {number} [x] 1211 * 1212 * @param {number} [y] 1213 * 1214 * @param {number} [width] 1215 * 1216 * @param {number} [height] 1217 * 1218 * @return {Highcharts.ClipRectElement} 1219 * A clipping rectangle. 1220 */ 1221 clipRect(x, y, width, height) { 1222 return this.rect(x, y, width, height, 0); 1223 } 1224 /** 1225 * Draw text. The text can contain a subset of HTML, like spans and anchors 1226 * and some basic text styling of these. For more advanced features like 1227 * border and background, use {@link Highcharts.SVGRenderer#label} instead. 1228 * To update the text after render, run `text.attr({ text: 'New text' })`. 1229 * 1230 * @sample highcharts/members/renderer-text-on-chart/ 1231 * Annotate the chart freely 1232 * @sample highcharts/members/renderer-on-chart/ 1233 * Annotate with a border and in response to the data 1234 * @sample highcharts/members/renderer-text/ 1235 * Formatted text 1236 * 1237 * @function Highcharts.SVGRenderer#text 1238 * 1239 * @param {string} [str] 1240 * The text of (subset) HTML to draw. 1241 * 1242 * @param {number} [x] 1243 * The x position of the text's lower left corner. 1244 * 1245 * @param {number} [y] 1246 * The y position of the text's lower left corner. 1247 * 1248 * @param {boolean} [useHTML=false] 1249 * Use HTML to render the text. 1250 * 1251 * @return {Highcharts.SVGElement} 1252 * The text object. 1253 */ 1254 text(str, x, y, useHTML) { 1255 const renderer = this, attribs = {}; 1256 if (useHTML && (renderer.allowHTML || !renderer.forExport)) { 1257 return renderer.html(str, x, y); 1258 } 1259 attribs.x = Math.round(x || 0); // X always needed for line-wrap logic 1260 if (y) { 1261 attribs.y = Math.round(y); 1262 } 1263 if (defined(str)) { 1264 attribs.text = str; 1265 } 1266 const wrapper = renderer.createElement('text').attr(attribs); 1267 if (!useHTML || (renderer.forExport && !renderer.allowHTML)) { 1268 wrapper.xSetter = function (value, key, element) { 1269 const tspans = element.getElementsByTagName('tspan'), parentVal = element.getAttribute(key); 1270 for (let i = 0, tspan; i < tspans.length; i++) { 1271 tspan = tspans[i]; 1272 // If the x values are equal, the tspan represents a line 1273 // break 1274 if (tspan.getAttribute(key) === parentVal) { 1275 tspan.setAttribute(key, value); 1276 } 1277 } 1278 element.setAttribute(key, value); 1279 }; 1280 } 1281 return wrapper; 1282 } 1283 /** 1284 * Utility to return the baseline offset and total line height from the font 1285 * size. 1286 * 1287 * @function Highcharts.SVGRenderer#fontMetrics 1288 * 1289 * @param {Highcharts.SVGElement|Highcharts.SVGDOMElement|number} [element] 1290 * The element to inspect for a current font size. If a number is 1291 * given, it's used as a fall back for direct font size in pixels. 1292 * 1293 * @return {Highcharts.FontMetricsObject} 1294 * The font metrics. 1295 */ 1296 fontMetrics(element) { 1297 const f = pInt(SVGElement.prototype.getStyle.call(element, 'font-size') || 0); 1298 // Empirical values found by comparing font size and bounding box 1299 // height. Applies to the default font family. 1300 // https://jsfiddle.net/highcharts/7xvn7/ 1301 const h = f < 24 ? f + 3 : Math.round(f * 1.2), b = Math.round(h * 0.8); 1302 return { 1303 // Line height 1304 h, 1305 // Baseline 1306 b, 1307 // Font size 1308 f 1309 }; 1310 } 1311 /** 1312 * Correct X and Y positioning of a label for rotation (#1764). 1313 * 1314 * @private 1315 * @function Highcharts.SVGRenderer#rotCorr 1316 */ 1317 rotCorr(baseline, rotation, alterY) { 1318 let y = baseline; 1319 if (rotation && alterY) { 1320 y = Math.max(y * Math.cos(rotation * deg2rad), 4); 1321 } 1322 return { 1323 x: (-baseline / 3) * Math.sin(rotation * deg2rad), 1324 y: y 1325 }; 1326 } 1327 /** 1328 * Compatibility function to convert the legacy one-dimensional path array 1329 * into an array of segments. 1330 * 1331 * It is used in maps to parse the `path` option, and in SVGRenderer.dSetter 1332 * to support legacy paths from demos. 1333 * 1334 * @private
vendor: 9,993 bytes, lines 1334-1575
1334 1335 * @function Highcharts.SVGRenderer#pathToSegments 1336 */ 1337 pathToSegments(path) { 1338 const ret = []; 1339 const segment = []; 1340 const commandLength = { 1341 A: 8, 1342 C: 7, 1343 H: 2, 1344 L: 3, 1345 M: 3, 1346 Q: 5, 1347 S: 5, 1348 T: 3, 1349 V: 2 1350 }; 1351 // Short, non-typesafe parsing of the one-dimensional array. It splits 1352 // the path on any string. This is not type checked against the tuple 1353 // types, but is shorter, and doesn't require specific checks for any 1354 // command type in SVG. 1355 for (let i = 0; i < path.length; i++) { 1356 // Command skipped, repeat previous or insert L/l for M/m 1357 if (isString(segment[0]) && 1358 isNumber(path[i]) && 1359 segment.length === commandLength[(segment[0].toUpperCase())]) { 1360 path.splice(i, 0, segment[0].replace('M', 'L').replace('m', 'l')); 1361 } 1362 // Split on string 1363 if (typeof path[i] === 'string') { 1364 if (segment.length) { 1365 ret.push(segment.slice(0)); 1366 } 1367 segment.length = 0; 1368 } 1369 segment.push(path[i]); 1370 } 1371 ret.push(segment.slice(0)); 1372 return ret; 1373 /* 1374 // Fully type-safe version where each tuple type is checked. The 1375 // downside is filesize and a lack of flexibility for unsupported 1376 // commands 1377 const ret: SVGPath = [], 1378 commands = { 1379 A: 7, 1380 C: 6, 1381 H: 1, 1382 L: 2, 1383 M: 2, 1384 Q: 4, 1385 S: 4, 1386 T: 2, 1387 V: 1, 1388 Z: 0 1389 }; 1390 1391 let i = 0, 1392 lastI = 0, 1393 lastCommand; 1394 1395 while (i < path.length) { 1396 const item = path[i]; 1397 1398 let command; 1399 1400 if (typeof item === 'string') { 1401 command = item; 1402 i += 1; 1403 } else { 1404 command = lastCommand || 'M'; 1405 } 1406 1407 // Upper case 1408 const commandUC = command.toUpperCase(); 1409 1410 if (commandUC in commands) { 1411 1412 // No numeric parameters 1413 if (command === 'Z' || command === 'z') { 1414 ret.push([command]); 1415 1416 // One numeric parameter 1417 } else { 1418 const val0 = path[i]; 1419 if (typeof val0 === 'number') { 1420 1421 // Horizontal line to 1422 if (command === 'H' || command === 'h') { 1423 ret.push([command, val0]); 1424 i += 1; 1425 1426 // Vertical line to 1427 } else if (command === 'V' || command === 'v') { 1428 ret.push([command, val0]); 1429 i += 1; 1430 1431 // Two numeric parameters 1432 } else { 1433 const val1 = path[i + 1]; 1434 if (typeof val1 === 'number') { 1435 // lineTo 1436 if (command === 'L' || command === 'l') { 1437 ret.push([command, val0, val1]); 1438 i += 2; 1439 1440 // moveTo 1441 } else if (command === 'M' || command === 'm') { 1442 ret.push([command, val0, val1]); 1443 i += 2; 1444 1445 // Smooth quadratic bezier 1446 } else if (command === 'T' || command === 't') { 1447 ret.push([command, val0, val1]); 1448 i += 2; 1449 1450 // Four numeric parameters 1451 } else { 1452 const val2 = path[i + 2], 1453 val3 = path[i + 3]; 1454 if ( 1455 typeof val2 === 'number' && 1456 typeof val3 === 'number' 1457 ) { 1458 // Quadratic bezier to 1459 if ( 1460 command === 'Q' || 1461 command === 'q' 1462 ) { 1463 ret.push([ 1464 command, 1465 val0, 1466 val1, 1467 val2, 1468 val3 1469 ]); 1470 i += 4; 1471 1472 // Smooth cubic bezier to 1473 } else if ( 1474 command === 'S' || 1475 command === 's' 1476 ) { 1477 ret.push([ 1478 command, 1479 val0, 1480 val1, 1481 val2, 1482 val3 1483 ]); 1484 i += 4; 1485 1486 // Six numeric parameters 1487 } else { 1488 const val4 = path[i + 4], 1489 val5 = path[i + 5]; 1490 1491 if ( 1492 typeof val4 === 'number' && 1493 typeof val5 === 'number' 1494 ) { 1495 // Curve to 1496 if ( 1497 command === 'C' || 1498 command === 'c' 1499 ) { 1500 ret.push([ 1501 command, 1502 val0, 1503 val1, 1504 val2, 1505 val3, 1506 val4, 1507 val5 1508 ]); 1509 i += 6; 1510 1511 // Seven numeric parameters 1512 } else { 1513 const val6 = path[i + 6]; 1514 1515 // Arc to 1516 if ( 1517 typeof val6 === 1518 'number' && 1519 ( 1520 command === 'A' || 1521 command === 'a' 1522 ) 1523 ) { 1524 ret.push([ 1525 command, 1526 val0, 1527 val1, 1528 val2, 1529 val3, 1530 val4, 1531 val5, 1532 val6 1533 ]); 1534 i += 7; 1535 1536 } 1537 1538 } 1539 } 1540 } 1541 } 1542 } 1543 } 1544 1545 } 1546 } 1547 } 1548 } 1549 1550 // An unmarked command following a moveTo is a lineTo 1551 lastCommand = command === 'M' ? 'L' : command; 1552 1553 if (i === lastI) { 1554 break; 1555 } 1556 lastI = i; 1557 } 1558 return ret; 1559 */ 1560 } 1561 /** 1562 * Draw a label, which is an extended text element with support for border 1563 * and background. Highcharts creates a `g` element with a text and a `path` 1564 * or `rect` inside, to make it behave somewhat like a HTML div. Border and 1565 * background are set through `stroke`, `stroke-width` and `fill` attributes 1566 * using the {@link Highcharts.SVGElement#attr|attr} method. To update the 1567 * text after render, run `label.attr({ text: 'New text' })`. 1568 * 1569 * @sample highcharts/members/renderer-label-on-chart/ 1570 * A label on the chart 1571 * 1572 * @function Highcharts.SVGRenderer#label 1573 * 1574 * @param {string} str 1575 *
1575 The initial text string or (subset) HTML to render. 1576 * 1577 * @param {number} x 1578 * The x position of the label's left side. 1579 * 1580 * @param {number} [y] 1581 * The y position of the label's top side or baseline, depending on 1582 * the `baseline` parameter. 1583 * 1584 * @param {string} [shape='rect'] 1585 * The shape of the label's border/background, if any. Defaults to 1586 * `rect`. Other possible values are `callout` or other shapes 1587 * defined in {@link Highcharts.SVGRenderer#symbols}. 1588 * 1589 * @param {number} [anchorX] 1590 * In case the `shape` has a pointer, like a flag, this is the 1591 * coordinates it should be pinned to. 1592 * 1593 * @param {number} [anchorY] 1594 * In case the `shape` has a pointer, like a flag, this is the 1595 * coordinates it should be pinned to. 1596 * 1597 * @param {boolean} [useHTML=false] 1598 * Whether to use HTML to render the label. 1599 * 1600 * @param {boolean} [baseline=false] 1601 * Whether to position the label relative to the text baseline, 1602 * like {@link Highcharts.SVGRenderer#text|renderer.text}, or to the 1603 * upper border of the rectangle. 1604 * 1605 * @param {string} [className] 1606 * Class name for the group. 1607 * 1608 * @return {Highcharts.SVGElement} 1609 * The generated label. 1610 */ 1611 label(str, x, y, shape, anchorX, anchorY, useHTML, baseline, className) { 1612 return new SVGLabel(this, str, x, y, shape, anchorX, anchorY, useHTML, baseline, className); 1613 } 1614 /** 1615 * Re-align all aligned elements. 1616 * 1617 * @private 1618 * @function Highcharts.SVGRenderer#alignElements 1619 */ 1620 alignElements() { 1621 this.alignedObjects.forEach((el) => el.align()); 1622 } 1623} 1624extend(SVGRenderer.prototype, { 1625 /** 1626 * A pointer to the renderer's associated Element class. 1627 * 1628 * @name Highcharts.SVGRenderer#Element 1629 * @type {Highcharts.SVGElement} 1630 */ 1631 Element: SVGElement, 1632 SVG_NS, 1633 /** 1634 * A collection of characters mapped to HTML entities. When `useHTML` on an 1635 * element is true, these entities will be rendered correctly by HTML. In 1636 * the SVG pseudo-HTML, they need to be unescaped back to simple characters, 1637 * so for example `<` will render as `<`. 1638 * 1639 * @example 1640 * // Add support for unescaping quotes 1641 * Highcharts.SVGRenderer.prototype.escapes['"'] = '"'; 1642 * 1643 * @name Highcharts.SVGRenderer#escapes 1644 * @type {Highcharts.Dictionary<string>} 1645 */ 1646 escapes: { 1647 '&': '&', 1648 '<': '<', 1649 '>': '>', 1650 "'": ''', // eslint-disable-line quotes 1651 '"': '"' 1652 }, 1653 /** 1654 * An extendable collection of functions for defining symbol paths. 1655 * 1656 * @name Highcharts.SVGRenderer#symbols 1657 * @type {Highcharts.SymbolDictionary} 1658 */ 1659 symbols: Symbols, 1660 /** 1661 * Dummy function for plugins, called every time the renderer is updated. 1662 * Prior to Highcharts 5, this was used for the canvg renderer. 1663 * 1664 * @deprecated 1665 * @function Highcharts.SVGRenderer#draw 1666 */ 1667 draw: noop 1668}); 1669/* * 1670 * 1671 * Registry 1672 * 1673 * */ 1674RendererRegistry.registerRendererType('svg', SVGRenderer, true); 1675/* * 1676 * 1677 * Export Default 1678 * 1679 * */ 1680export default SVGRenderer; 1681/* * 1682 * 1683 * API Declarations 1684 * 1685 * */ 1686/** 1687 * A clipping rectangle that can be applied to one or more {@link SVGElement} 1688 * instances. It is instantiated with the {@link SVGRenderer#clipRect} function 1689 * and applied with the {@link SVGElement#clip} function. 1690 * 1691 * @example 1692 * let circle = renderer.circle(100, 100, 100) 1693 * .attr({ fill: 'red' }) 1694 * .add(); 1695 * let clipRect = renderer.clipRect(100, 100, 100, 100); 1696 * 1697 * // Leave only the lower right quarter visible 1698 * circle.clip(clipRect); 1699 * 1700 * @typedef {Highcharts.SVGElement} Highcharts.ClipRectElement 1701 */ 1702/** 1703 * The font metrics. 1704 * 1705 * @interface Highcharts.FontMetricsObject 1706 */ /** 1707* The baseline relative to the top of the box. 1708* 1709* @name Highcharts.FontMetricsObject#b 1710* @type {number} 1711*/ /** 1712* The font size. 1713* 1714* @name Highcharts.FontMetricsObject#f 1715* @type {number} 1716*/ /** 1717* The line height. 1718* 1719* @name Highcharts.FontMetricsObject#h 1720* @type {number} 1721*/ 1722/**
1723 * An object containing `x` and `y` properties for the position of an element. 1724 * 1725 * @interface Highcharts.PositionObject 1726 */ /** 1727* X position of the element. 1728* @name Highcharts.PositionObject#x 1729* @type {number} 1730*/ /** 1731* Y position of the element. 1732* @name Highcharts.PositionObject#y 1733* @type {number} 1734*/ 1735/** 1736 * A rectangle. 1737 * 1738 * @interface Highcharts.RectangleObject 1739 */ /** 1740* Height of the rectangle. 1741* @name Highcharts.RectangleObject#height 1742* @type {number} 1743*/ /** 1744* Width of the rectangle. 1745* @name Highcharts.RectangleObject#width 1746* @type {number} 1747*/ /** 1748* Horizontal position of the rectangle. 1749* @name Highcharts.RectangleObject#x 1750* @type {number} 1751*/ /** 1752* Vertical position of the rectangle. 1753* @name Highcharts.RectangleObject#y 1754* @type {number} 1755*/ 1756/** 1757 * The shadow options. 1758 * 1759 * @interface Highcharts.ShadowOptionsObject 1760 */ /** 1761* The shadow color. 1762* @name Highcharts.ShadowOptionsObject#color 1763* @type {Highcharts.ColorString|undefined} 1764* @default ${palette.neutralColor100} 1765*/ /** 1766* The horizontal offset from the element. 1767* 1768* @name Highcharts.ShadowOptionsObject#offsetX 1769* @type {number|undefined} 1770* @default 1 1771*/ /** 1772* The vertical offset from the element. 1773* @name Highcharts.ShadowOptionsObject#offsetY 1774* @type {number|undefined} 1775* @default 1 1776*/ /** 1777* The shadow opacity. 1778* 1779* @name Highcharts.ShadowOptionsObject#opacity 1780* @type {number|undefined} 1781* @default 0.15 1782*/ /** 1783* The shadow width or distance from the element. 1784* @name Highcharts.ShadowOptionsObject#width 1785* @type {number|undefined} 1786* @default 3 1787*/ 1788/** 1789 * @interface Highcharts.SizeObject 1790 */ /** 1791* @name Highcharts.SizeObject#height 1792* @type {number} 1793*/ /** 1794* @name Highcharts.SizeObject#width 1795* @type {number} 1796*/ 1797/** 1798 * Array of path commands, that will go into the `d` attribute of an SVG 1799 * element. 1800 * 1801 * @typedef {Array<(Array<Highcharts.SVGPathCommand>|Array<Highcharts.SVGPathCommand,number>|Array<Highcharts.SVGPathCommand,number,number>|Array<Highcharts.SVGPathCommand,number,number,number,number>|Array<Highcharts.SVGPathCommand,number,number,number,number,number,number>|Array<Highcharts.SVGPathCommand,number,number,number,number,number,number,number>)>} Highcharts.SVGPathArray 1802 */ 1803/** 1804 * Possible path commands in an SVG path array. Valid values are `A`, `C`, `H`, 1805 * `L`, `M`, `Q`, `S`, `T`, `V`, `Z`. 1806 * 1807 * @typedef {string} Highcharts.SVGPathCommand 1808 * @validvalue ["a","c","h","l","m","q","s","t","v","z","A","C","H","L","M","Q","S","T","V","Z"] 1809 */ 1810/** 1811 * An extendable collection of functions for defining symbol paths. Symbols are 1812 * used internally for point markers, button and label borders and backgrounds, 1813 * or custom shapes. Extendable by adding to {@link SVGRenderer#symbols}. 1814 * 1815 * @interface Highcharts.SymbolDictionary 1816 */ /** 1817* @name Highcharts.SymbolDictionary#[key:string] 1818* @type {Function|undefined} 1819*/ /** 1820* @name Highcharts.SymbolDictionary#arc 1821* @type {Function|undefined} 1822*/ /** 1823* @name Highcharts.SymbolDictionary#callout 1824* @type {Function|undefined} 1825*/ /** 1826* @name Highcharts.SymbolDictionary#circle 1827* @type {Function|undefined} 1828*/ /** 1829* @name Highcharts.SymbolDictionary#diamond 1830* @type {Function|undefined} 1831*/ /** 1832* @name Highcharts.SymbolDictionary#square 1833* @type {Function|undefined} 1834*/ /** 1835* @name Highcharts.SymbolDictionary#triangle 1836* @type {Function|undefined} 1837*/ 1838/** 1839 * Can be one of `arc`, `callout`, `circle`, `diamond`, `square`, `triangle`, 1840 * and `triangle-down`. Symbols are used internally for point markers, button 1841 * and label borders and backgrounds, or custom shapes. Extendable by adding to 1842 * {@link SVGRenderer#symbols}. 1843 * 1844 * @typedef {"arc"|"callout"|"circle"|"diamond"|"square"|"triangle"|"triangle-down"} Highcharts.SymbolKeyValue 1845 */ 1846/** 1847 * Additional options, depending on the actual symbol drawn. 1848 * 1849 * @interface Highcharts.SymbolOptionsObject 1850 */ /** 1851* The anchor X position for the `callout` symbol. This is where the chevron 1852* points to. 1853* 1854* @name Highcharts.SymbolOptionsObject#anchorX 1855* @type {number|undefined} 1856*/ /** 1857* The anchor Y position for the `callout` symbol. This is where the chevron 1858* points to. 1859* 1860* @name Highcharts.SymbolOptionsObject#anchorY 1861* @type {number|undefined} 1862*/ /** 1863* The end angle of an `arc` symbol. 1864* 1865* @name Highcharts.SymbolOptionsObject#end 1866* @type {number|undefined} 1867*/ /** 1868* Whether to draw `arc` symbol open or closed. 1869* 1870* @name Highcharts.SymbolOptionsObject#open 1871* @type {boolean|undefined} 1872*/ /** 1873* The radius of an `arc` symbol, or the border radius for the `callout` symbol. 1874* 1875* @name Highcharts.SymbolOptionsObject#r 1876* @type {number|undefined} 1877*/ /** 1878* The start angle of an `arc` symbol. 1879* 1880* @name Highcharts.SymbolOptionsObject#start 1881* @type {number|undefined} 1882*/ 1883(''); // Keeps doclets above in transpiled file
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.