]> _ Git - fluidbook-html5.git/commitdiff
wait #7092 @1.5
authorVincent Vanwaelscappel <vincent@cubedesigners.com>
Mon, 30 Sep 2024 16:14:58 +0000 (18:14 +0200)
committerVincent Vanwaelscappel <vincent@cubedesigners.com>
Mon, 30 Sep 2024 16:14:58 +0000 (18:14 +0200)
js/libs/fluidbook/fluidbook.js
js/libs/fluidbook/fluidbook.pagetransitions.js
js/libs/fluidbook/fluidbook.utils.js
style/fluidbook.less

index e43d3736ffcee81e6e419b2431217f32c2f4f04b..fd900e2fd0fb7de67ea311cfe248189f26fdd837 100644 (file)
@@ -177,6 +177,12 @@ Fluidbook.prototype = {
         this.help = new FluidbookHelp(this);
         this.articles = new FluidbookArticles(this);
 
+        try {
+            $('head').append('<style>#shadow > .shadow{' + new Solver(new Color(this.settings.bookShadeColor[0], this.settings.bookShadeColor[1], this.settings.bookShadeColor[2])).solve().filter + '}</style>');
+        } catch (e) {
+
+        }
+
 
         $(this).trigger('fluidbook.lib.ready');
 
@@ -698,6 +704,7 @@ Fluidbook.prototype = {
             }
         }
 
+
         var s = $("#shadow,#edges");
 
         var s_in = [];
index cff6290a57295a3c42bf8fff72a0a8b23d44d8cf..2c541509c4b345a8b5525111b46458831bbe59e1 100644 (file)
@@ -306,7 +306,8 @@ FluidbookPageTransition.prototype = {
 
     centerBook: function (center, animationDuration) {
         var animate = animationDuration !== undefined && animationDuration > 0;
-        var move = $("#center-fluidbook,#center-shadow,#l_tabs .tabs");
+        var moveTransform = $("#center-fluidbook,#l_tabs .tabs");
+        var move = $("#center-shadow");
         var currentLeft = $("#center-fluidbook").data('left');
         var left = 0;
         if (center === undefined) {
@@ -324,14 +325,17 @@ FluidbookPageTransition.prototype = {
 
         if (animate) {
             $(move).addClass('animate');
+            $(moveTransform).addClass('animate');
         } else {
             $(move).removeClass('animate');
+            $(moveTransform).removeClass('animate');
         }
 
         var $this = this;
         var delay = this.fluidbook.support.android ? this.fluidbook.settings.mobileTransitionDuration * 1000 : 10;
         setTimeout(function () {
-            move.transform({translateX: left + 'px'});
+            moveTransform.transform({translateX: left + 'px'});
+            move.css('left', left);
             $this.fluidbook.resize.updateFluidbookRect();
         }, delay);
     },
index c3c832c83c67c89d15b6159e087db765208b7c15..8ccf07ed97322e7faf5fd93622e7d722a7d03f67 100644 (file)
@@ -181,3 +181,252 @@ function relayIframeScrollToView(iframe) {
 
 
 }
+
+class Color {
+    constructor(r, g, b) {
+        this.set(r, g, b);
+    }
+
+    toString() {
+        return `rgb(${Math.round(this.r)}, ${Math.round(this.g)}, ${Math.round(this.b)})`;
+    }
+
+    set(r, g, b) {
+        this.r = this.clamp(r);
+        this.g = this.clamp(g);
+        this.b = this.clamp(b);
+    }
+
+    hueRotate(angle = 0) {
+        angle = angle / 180 * Math.PI;
+        let sin = Math.sin(angle);
+        let cos = Math.cos(angle);
+
+        this.multiply([
+            0.213 + cos * 0.787 - sin * 0.213, 0.715 - cos * 0.715 - sin * 0.715, 0.072 - cos * 0.072 + sin * 0.928,
+            0.213 - cos * 0.213 + sin * 0.143, 0.715 + cos * 0.285 + sin * 0.140, 0.072 - cos * 0.072 - sin * 0.283,
+            0.213 - cos * 0.213 - sin * 0.787, 0.715 - cos * 0.715 + sin * 0.715, 0.072 + cos * 0.928 + sin * 0.072
+        ]);
+    }
+
+    grayscale(value = 1) {
+        this.multiply([
+            0.2126 + 0.7874 * (1 - value), 0.7152 - 0.7152 * (1 - value), 0.0722 - 0.0722 * (1 - value),
+            0.2126 - 0.2126 * (1 - value), 0.7152 + 0.2848 * (1 - value), 0.0722 - 0.0722 * (1 - value),
+            0.2126 - 0.2126 * (1 - value), 0.7152 - 0.7152 * (1 - value), 0.0722 + 0.9278 * (1 - value)
+        ]);
+    }
+
+    sepia(value = 1) {
+        this.multiply([
+            0.393 + 0.607 * (1 - value), 0.769 - 0.769 * (1 - value), 0.189 - 0.189 * (1 - value),
+            0.349 - 0.349 * (1 - value), 0.686 + 0.314 * (1 - value), 0.168 - 0.168 * (1 - value),
+            0.272 - 0.272 * (1 - value), 0.534 - 0.534 * (1 - value), 0.131 + 0.869 * (1 - value)
+        ]);
+    }
+
+    saturate(value = 1) {
+        this.multiply([
+            0.213 + 0.787 * value, 0.715 - 0.715 * value, 0.072 - 0.072 * value,
+            0.213 - 0.213 * value, 0.715 + 0.285 * value, 0.072 - 0.072 * value,
+            0.213 - 0.213 * value, 0.715 - 0.715 * value, 0.072 + 0.928 * value
+        ]);
+    }
+
+    multiply(matrix) {
+        let newR = this.clamp(this.r * matrix[0] + this.g * matrix[1] + this.b * matrix[2]);
+        let newG = this.clamp(this.r * matrix[3] + this.g * matrix[4] + this.b * matrix[5]);
+        let newB = this.clamp(this.r * matrix[6] + this.g * matrix[7] + this.b * matrix[8]);
+        this.r = newR;
+        this.g = newG;
+        this.b = newB;
+    }
+
+    brightness(value = 1) {
+        this.linear(value);
+    }
+
+    contrast(value = 1) {
+        this.linear(value, -(0.5 * value) + 0.5);
+    }
+
+    linear(slope = 1, intercept = 0) {
+        this.r = this.clamp(this.r * slope + intercept * 255);
+        this.g = this.clamp(this.g * slope + intercept * 255);
+        this.b = this.clamp(this.b * slope + intercept * 255);
+    }
+
+    invert(value = 1) {
+        this.r = this.clamp((value + (this.r / 255) * (1 - 2 * value)) * 255);
+        this.g = this.clamp((value + (this.g / 255) * (1 - 2 * value)) * 255);
+        this.b = this.clamp((value + (this.b / 255) * (1 - 2 * value)) * 255);
+    }
+
+    hsl() { // Code taken from https://stackoverflow.com/a/9493060/2688027, licensed under CC BY-SA.
+        let r = this.r / 255;
+        let g = this.g / 255;
+        let b = this.b / 255;
+        let max = Math.max(r, g, b);
+        let min = Math.min(r, g, b);
+        let h, s, l = (max + min) / 2;
+
+        if (max === min) {
+            h = s = 0;
+        } else {
+            let d = max - min;
+            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
+            switch (max) {
+                case r:
+                    h = (g - b) / d + (g < b ? 6 : 0);
+                    break;
+                case g:
+                    h = (b - r) / d + 2;
+                    break;
+                case b:
+                    h = (r - g) / d + 4;
+                    break;
+            }
+            h /= 6;
+        }
+
+        return {
+            h: h * 100,
+            s: s * 100,
+            l: l * 100
+        };
+    }
+
+    clamp(value) {
+        if (value > 255) {
+            value = 255;
+        } else if (value < 0) {
+            value = 0;
+        }
+        return value;
+    }
+}
+
+class Solver {
+    constructor(target) {
+        this.target = target;
+        this.targetHSL = target.hsl();
+        this.reusedColor = new Color(0, 0, 0); // Object pool
+    }
+
+    solve() {
+        let result = this.solveNarrow(this.solveWide());
+        return {
+            values: result.values,
+            loss: result.loss,
+            filter: this.css(result.values)
+        };
+    }
+
+    solveWide() {
+        const A = 5;
+        const c = 15;
+        const a = [60, 180, 18000, 600, 1.2, 1.2];
+
+        let best = {loss: Infinity};
+        for (let i = 0; best.loss > 25 && i < 3; i++) {
+            let initial = [50, 20, 3750, 50, 100, 100];
+            let result = this.spsa(A, a, c, initial, 1000);
+            if (result.loss < best.loss) {
+                best = result;
+            }
+        }
+        return best;
+    }
+
+    solveNarrow(wide) {
+        const A = wide.loss;
+        const c = 2;
+        const A1 = A + 1;
+        const a = [0.25 * A1, 0.25 * A1, A1, 0.25 * A1, 0.2 * A1, 0.2 * A1];
+        return this.spsa(A, a, c, wide.values, 500);
+    }
+
+    spsa(A, a, c, values, iters) {
+        const alpha = 1;
+        const gamma = 0.16666666666666666;
+
+        let best = null;
+        let bestLoss = Infinity;
+        let deltas = new Array(6);
+        let highArgs = new Array(6);
+        let lowArgs = new Array(6);
+
+        for (let k = 0; k < iters; k++) {
+            let ck = c / Math.pow(k + 1, gamma);
+            for (let i = 0; i < 6; i++) {
+                deltas[i] = Math.random() > 0.5 ? 1 : -1;
+                highArgs[i] = values[i] + ck * deltas[i];
+                lowArgs[i] = values[i] - ck * deltas[i];
+            }
+
+            let lossDiff = this.loss(highArgs) - this.loss(lowArgs);
+            for (let i = 0; i < 6; i++) {
+                let g = lossDiff / (2 * ck) * deltas[i];
+                let ak = a[i] / Math.pow(A + k + 1, alpha);
+                values[i] = fix(values[i] - ak * g, i);
+            }
+
+            let loss = this.loss(values);
+            if (loss < bestLoss) {
+                best = values.slice(0);
+                bestLoss = loss;
+            }
+        }
+        return {values: best, loss: bestLoss};
+
+        function fix(value, idx) {
+            let max = 100;
+            if (idx === 2 /* saturate */) {
+                max = 7500;
+            } else if (idx === 4 /* brightness */ || idx === 5 /* contrast */) {
+                max = 200;
+            }
+
+            if (idx === 3 /* hue-rotate */) {
+                if (value > max) {
+                    value = value % max;
+                } else if (value < 0) {
+                    value = max + value % max;
+                }
+            } else if (value < 0) {
+                value = 0;
+            } else if (value > max) {
+                value = max;
+            }
+            return value;
+        }
+    }
+
+    loss(filters) { // Argument is array of percentages.
+        let color = this.reusedColor;
+        color.set(0, 0, 0);
+
+        color.invert(filters[0] / 100);
+        color.sepia(filters[1] / 100);
+        color.saturate(filters[2] / 100);
+        color.hueRotate(filters[3] * 3.6);
+        color.brightness(filters[4] / 100);
+        color.contrast(filters[5] / 100);
+
+        let colorHSL = color.hsl();
+        return Math.abs(color.r - this.target.r)
+            + Math.abs(color.g - this.target.g)
+            + Math.abs(color.b - this.target.b)
+            + Math.abs(colorHSL.h - this.targetHSL.h)
+            + Math.abs(colorHSL.s - this.targetHSL.s)
+            + Math.abs(colorHSL.l - this.targetHSL.l);
+    }
+
+    css(filters) {
+        function fmt(idx, multiplier = 1) {
+            return Math.round(filters[idx] * multiplier);
+        }
+
+        return `filter: invert(${fmt(0)}%) sepia(${fmt(1)}%) saturate(${fmt(2)}%) hue-rotate(${fmt(3, 3.6)}deg) brightness(${fmt(4)}%) contrast(${fmt(5)}%);`;
+    }
+}
index 8edb6306a109d049b1e8a8ecf1189b7e6abf0b1c..f62b6ad94d21b394dce721a4fe0d410ca0f0c0c8 100644 (file)
@@ -709,7 +709,7 @@ body, html {
   width: unit(@book-page-width*2, px);
   height: unit(@book-page-height, px);
   pointer-events: none;
-  mix-blend-mode: multiply;
+  mix-blend-mode: @shadow-blend-mode;
 
   transition-property: none !important;
   transition-duration: 0ms !important;