import * as React from "react"; import * as ReactDOM from "react-dom"; import { FilterResponse, FilterRequestProps } from "../../types"; import { Parser } from "collit"; import { isValidColor, normalizeHex } from "../../spinoffs/wcag-contrast"; function getMorphProps(radius: number) { return { operator: radius < 0 ? "erode" : "dilate", radius: Math.abs(radius) }; } export function Double({ fill, strokeWidth = 1, getNamespacedId }: FilterRequestProps): FilterResponse { const source = "SourceGraphic"; const hasFill = ["none", "transparent"].indexOf(fill) === -1; let filterPrimitives; const inPrimitiveName = "inDouble"; const in2PrimitiveName = "in2Double"; let inRadius; let compositeOperator; // almost impossible to see a double line if it's under 1px wide. const minStrokeWidth = Math.max(strokeWidth, 1); if (!hasFill) { compositeOperator = "out"; // Sets the width of the thick line. inRadius = minStrokeWidth; // Related to setting the width of the inner stripe that splits the thick // line, although visual inspection shows it's setting something else, // because the stripe width doesn't equal inRadius2 or 2 * inRadius2. // NOTE: FF seems to need this, but Chrome does not. const in2Radius = 1 / minStrokeWidth / 2; filterPrimitives = [ // darken , ]; } else { compositeOperator = "atop"; // Appears to be related to setting the outside line. const in2Radius = minStrokeWidth; // Appears to be related to setting the inside line. inRadius = -1 * minStrokeWidth; filterPrimitives = [ ]; } filterPrimitives.push( ); filterPrimitives.push( ); return { filterProperties: { id: getNamespacedId(["double", hasFill, strokeWidth, "filter"].join("-")), width: "200%", height: "200%", x: "-50%", y: "-50%" }, filterPrimitives: filterPrimitives }; } export function BlackToColor({ color, getNamespacedId }: FilterRequestProps): FilterResponse | "none" { const source = "SourceGraphic"; if (!isValidColor(color)) { return "none"; } const { rgb, hex } = Parser.parseColor(color); const { r, g, b, a } = rgb; const id = getNamespacedId( ["BlackTo", normalizeHex(hex), "filter"].join("-") ); return { filterProperties: { id: id, filterUnits: "userSpaceOnUse" }, filterPrimitives: [ ] }; } export function WhiteToColor({ color, getNamespacedId }: FilterRequestProps): FilterResponse | "none" { const source = "SourceGraphic"; if (!isValidColor(color)) { return "none"; } const { rgb, hex } = Parser.parseColor(color); const { r, g, b, a } = rgb; const id = getNamespacedId( ["WhiteTo", normalizeHex(hex), "filter"].join("-") ); return { filterProperties: { id: id, filterUnits: "userSpaceOnUse" }, filterPrimitives: [ ] }; } export function Highlight({ color, getNamespacedId }: FilterRequestProps): FilterResponse { const source = "SourceGraphic"; return { filterProperties: { id: getNamespacedId(["highlight", color, "filter"].join("-")), filterUnits: "userSpaceOnUse" }, filterPrimitives: [ /* Desaturate all colours before highlighting */ , , , , , ] }; } export function Round({ strokeWidth = 1, getNamespacedId }: FilterRequestProps): FilterResponse { const source = "SourceGraphic"; // Can we handle a strokeWidth of 0.4? //const roundedStrokeWidth = Math.max(1, Math.round(strokeWidth || 1)); // C' = slope * C + intercept // where C is the initial component (e.g., ‘feFuncR’), // C' is the remapped component; // both in the closed interval [0,1]. // http://www.w3.org/TR/filter-effects/#feComponentTransferElement const darkInputSlope = 1.5; const darkInputIntercept = 0; const darkOutputSlope = 4; const darkOutputIntercept = -0.7; const normalizedWidth = 3; //const strokeWidthNormalizationOperator = (strokeWidth > 2) ? 'contract' : 'dilate'; const strokeWidthNormalizationOperator = strokeWidth > normalizedWidth ? "contract" : "dilate"; // strangely, this is what appears needed to normalize stroke width to a value // large enough to be blurred without being destroyed: const radius = strokeWidthNormalizationOperator === "dilate" ? 1 : 0; // would have expected this, but it doesn't produce expected results: //const radius = (strokeWidthNormalizationOperator === 'dilate') ? (normalizedWidth - strokeWidth) : strokeWidth - normalizedWidth; //const radius = Math.abs((normalizedWidth - strokeWidth - 1) / 2 ); //const radius = Math.abs(normalizedWidth - strokeWidth); const strokeWidthRevertOperator = strokeWidthNormalizationOperator === "contract" ? "dilate" : "contract"; const normalizedDark = strokeWidth === 1 ? [ , , ] : [ , ]; return { filterProperties: { id: getNamespacedId(["round", strokeWidth, "filter"].join("-")) }, filterPrimitives: normalizedDark.concat([ , , , , ]) }; }