UNPKG

@amcharts/amcharts5

Version:
176 lines 10.1 kB
import { Color } from "../core/util/Color"; import { Theme } from "../core/Theme"; import { PatternSet } from "../core/util/PatternSet"; import { percent } from "../core/util/Percent"; import { setColor } from "./DefaultTheme"; import { LinePattern } from "../core/render/patterns/LinePattern"; import { CirclePattern } from "../core/render/patterns/CirclePattern"; import { RectanglePattern } from "../core/render/patterns/RectanglePattern"; import { StarPattern } from "../core/render/patterns/StarPattern"; import { TrianglePattern } from "../core/render/patterns/TrianglePattern"; /** * Builds a fresh, varied set of patterns. One set is made per theme rule (i.e. * per root), shared by all charts of that class — mirroring how the default * theme shares a single ColorSet per root. * * Angled hatches use each pattern's `angle` setting (which tiles seamlessly at a * small tile size) rather than rotating the whole pattern, and the set mixes in * dots, stars, triangles and grids so consecutive series stay easy to tell * apart by shape alone. */ export function buildPatterns(root, color) { return [ LinePattern.new(root, { width: 40, height: 40, angle: 45, gap: 5, strokeWidth: 1.5, color: color }), CirclePattern.new(root, { width: 11, height: 11, radius: 4, gap: 2, checkered: true, color: color }), RectanglePattern.new(root, { width: 15, height: 15, maxWidth: 6, maxHeight: 6, gap: 6, color: color }), StarPattern.new(root, { width: 16, height: 16, radius: 5, innerRadius: percent(45), spikes: 6, gap: 3, checkered: true, color: color }), TrianglePattern.new(root, { width: 16, height: 16, maxWidth: 8, maxHeight: 8, gap: 6, color: color }), StarPattern.new(root, { width: 40, height: 40, radius: 7, innerRadius: percent(65), spikes: 8, gap: 0, checkered: true, color: color }), LinePattern.new(root, { width: 22, height: 22, angle: 0, gap: 4, strokeWidth: 1, color: color }), RectanglePattern.new(root, { width: 14, height: 14, maxWidth: 11, maxHeight: 11, gap: 7, rotation: 45, rotateShapes: true, color: color }), RectanglePattern.new(root, { width: 22, height: 22, maxWidth: 1, maxHeight: 1, gap: 2, rotateShapes: true, color: color }), TrianglePattern.new(root, { width: 18, height: 18, maxWidth: 8, maxHeight: 8, gap: 2, rotation: 180, rotateShapes: true, checkered: true, color: color }), LinePattern.new(root, { width: 40, height: 40, angle: -45, gap: 5, strokeWidth: 1.5, color: color }), RectanglePattern.new(root, { width: 14, height: 14, maxWidth: 4, maxHeight: 4, gap: 2, rotation: 45, rotateShapes: true, checkered: true, color: color }) ]; } /** * Stroke widths cycled across line series (which can't carry a fill pattern), so * they are told apart by weight as well as tone. */ export const PATTERN_STROKE_WIDTHS = [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]; /** * Stroke dash arrays cycled across line series (0 = solid), paired with the * widths above for extra separation. */ export const PATTERN_STROKE_DASHARRAYS = [ 0, [6, 4], [2, 2], [10, 5, 2, 5], [4, 4], [3, 3], [12, 5], [8, 4, 2, 4], [3, 3], [14, 6], [2, 7], [6, 3, 2, 3] ]; /** * A ramp of gray fills cycled across series (ordered so neighbours contrast), so * series differ by tone as well as by their overlaid white pattern. Kept mid-dark * enough that the white texture always reads. */ export const PATTERN_GRAYS = [ Color.fromHex(0x4a4a4a), Color.fromHex(0x818181), Color.fromHex(0x606060), Color.fromHex(0x939393), Color.fromHex(0x545454), Color.fromHex(0x727272) ]; /** * "Patterns" — a monochrome, texture-driven theme in the spirit of engraved or * newspaper charts: every filled series shares one gray fill overlaid with a * distinct white pattern (hatch / dot / star / triangle / grid), so series are * told apart purely by texture rather than hue. * * Line series (which have no fill for a pattern to attach to) are all gray too * and are told apart by stroke width and dash. Because categories are encoded by * shape rather than hue, it prints cleanly and stays legible for all forms of * color blindness. It layers on the default (light) look. * * This is a standalone theme; it does not modify any built-in theme. * * @see {@link https://www.amcharts.com/docs/v5/concepts/colors-gradients-and-patterns/patterns/#Pattern_sets} for more info * @see {@link https://www.amcharts.com/docs/v5/concepts/themes/} for more info * @important */ export class PatternsTheme extends Theme { setupDefaultRules() { super.setupDefaultRules(); // White pattern shapes (gaps left transparent) drawn over a gray fill. const patternColor = Color.fromHex(0xffffff); // Black-and-white interface colors (no default blue). this.rule("InterfaceColors").setAll({ stroke: Color.fromHex(0x666666), fill: Color.fromHex(0xffffff), primaryButton: Color.fromHex(0x666666), primaryButtonHover: Color.fromHex(0x333333), primaryButtonDown: Color.fromHex(0x555555), primaryButtonActive: Color.fromHex(0x555555), primaryButtonDisabled: Color.fromHex(0xcccccc), primaryButtonTextDisabled: Color.fromHex(0xffffff), primaryButtonText: Color.fromHex(0xffffff), primaryButtonStroke: Color.fromHex(0x666666), secondaryButton: Color.fromHex(0xeeeeee), secondaryButtonHover: Color.fromHex(0xdddddd), secondaryButtonDown: Color.fromHex(0xcccccc), secondaryButtonActive: Color.fromHex(0xbbbbbb), secondaryButtonText: Color.fromHex(0x222222), secondaryButtonStroke: Color.fromHex(0x666666), grid: Color.fromHex(0x666666), background: Color.fromHex(0xffffff), alternativeBackground: Color.fromHex(0x666666), text: Color.fromHex(0x222222), alternativeText: Color.fromHex(0xffffff), disabled: Color.fromHex(0x999999), positive: Color.fromHex(0x555555), negative: Color.fromHex(0x222222) }); // A ramp of grays for the series: line strokes and fills cycle through them, // and the white pattern assigned per series reads as a light texture on top, // so series differ by both tone and texture. this.rule("ColorSet").setAll({ colors: PATTERN_GRAYS, reuse: true }); const ic = this._root.interfaceColors; // Columns, pie/funnel/venn slices and line-area fills all receive a distinct // white pattern per series from the PatternSet below, layered over their gray // fill - no per-shape rules are needed for them. // Hierarchy & flow series distribute a distinct white pattern per node from // their own PatternSet (assigned below), over the shared gray fill. Here we // only give each node shape a white outline to separate neighbours. Tags // mirror each default theme's node-shape rule exactly. const self = this; function patternNode(className, tags) { const rule = self.rule(className, tags); rule.setAll({ stroke: patternColor, strokeOpacity: 1 }); } [ ["RoundedRectangle", ["treemap", "node", "shape"]], ["RoundedRectangle", ["partition", "node", "shape"]], ["Slice", ["sunburst", "node", "shape"]], ["Circle", ["pack", "node", "shape"]], ["Circle", ["linkedhierarchy", "shape"]], ["Graphics", ["voronoitreemap", "node", "shape"]], ["RoundedRectangle", ["sankey", "node", "shape"]], ["Slice", ["chord", "node", "shape"]] // chord (flow) nodes ].forEach(function (entry) { patternNode(entry[0], entry[1]); }); // Map polygons: a fine white rectangle-dot pattern over a gray fill by // default, white 45deg lines when active. const mapRule = this.rule("MapPolygon"); mapRule.set("stroke", patternColor); mapRule.set("strokeOpacity", 1); mapRule.set("strokeWidth", .25); setColor(mapRule, "fill", ic, "disabled"); mapRule.set("fillPattern", RectanglePattern.new(this._root, { maxWidth: 1, maxHeight: 1, gap: 2, color: patternColor })); mapRule.states.create("active", { fillPattern: LinePattern.new(this._root, { angle: 45, gap: 2, strokeWidth: 1, color: patternColor }) }); // Assign a pattern set on the chart/series that support it, so each series // is given the next pattern automatically. A fresh set per root mirrors how // the default theme assigns a ColorSet. this.rule("XYChart").setAll({ patterns: PatternSet.new(this._root, { patterns: buildPatterns(this._root, patternColor) }), // Line series can't take a fill pattern, so vary their stroke instead. strokeWidths: PATTERN_STROKE_WIDTHS, strokeDasharrays: PATTERN_STROKE_DASHARRAYS }); this.rule("PercentSeries").set("patterns", PatternSet.new(this._root, { patterns: buildPatterns(this._root, patternColor) })); this.rule("Venn").set("patterns", PatternSet.new(this._root, { patterns: buildPatterns(this._root, patternColor) })); // Hierarchy (treemap, sunburst, pack, partition, force-directed) and flow // (sankey, chord) distribute a distinct pattern per node from their own set. this.rule("Hierarchy").set("patterns", PatternSet.new(this._root, { patterns: buildPatterns(this._root, patternColor) })); this.rule("FlowNodes").set("patterns", PatternSet.new(this._root, { patterns: buildPatterns(this._root, patternColor) })); } } //# sourceMappingURL=PatternsTheme.js.map