@unabridged/midwest 0.16.1 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/assets/javascript/midwest/index.ts +2 -0
- package/app/assets/javascript/midwest.js +563 -6
- package/app/assets/javascript/midwest.js.map +1 -1
- package/app/assets/stylesheets/midwest.css +1 -1
- package/app/assets/stylesheets/midwest.tailwind.css +3 -1
- package/dist/css/midwest.css +1 -1
- package/dist/javascript/collection/app/assets/javascript/midwest/index.js +2 -0
- package/dist/javascript/collection/app/assets/javascript/midwest/index.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/carousel_component/carousel_component_controller.js +17 -5
- package/dist/javascript/collection/app/components/midwest/carousel_component/carousel_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/image_component/color_thief.js +490 -0
- package/dist/javascript/collection/app/components/midwest/image_component/color_thief.js.map +1 -0
- package/dist/javascript/collection/app/components/midwest/image_component/image_component_controller.js +47 -0
- package/dist/javascript/collection/app/components/midwest/image_component/image_component_controller.js.map +1 -0
- package/dist/javascript/collection/app/components/midwest/tabs_component/tabs_component_controller.js +15 -1
- package/dist/javascript/collection/app/components/midwest/tabs_component/tabs_component_controller.js.map +1 -1
- package/dist/javascript/midwest.js +563 -6
- package/dist/javascript/midwest.js.map +1 -1
- package/package.json +1 -1
|
@@ -18,6 +18,7 @@ import Chart from '../../../components/midwest/chart_component/chart_component_c
|
|
|
18
18
|
import Range from '../../../components/midwest/form/range_component/range_component_controller'
|
|
19
19
|
import Rating from '../../../components/midwest/rating_component/rating_component_controller'
|
|
20
20
|
import Autocomplete from '../../../components/midwest/form/autocomplete_component/autocomplete_component_controller'
|
|
21
|
+
import Image from '../../../components/midwest/image_component/image_component_controller'
|
|
21
22
|
/* IMPORTS */
|
|
22
23
|
|
|
23
24
|
export { Card, Banner, CountdownTimer, Chart }
|
|
@@ -43,5 +44,6 @@ export function registerMidwestControllers (application: any) {
|
|
|
43
44
|
application.register('midwest-range', Range)
|
|
44
45
|
application.register('midwest-rating', Rating)
|
|
45
46
|
application.register('midwest-autocomplete', Autocomplete)
|
|
47
|
+
application.register('midwest-image', Image)
|
|
46
48
|
/* EXPORTS */
|
|
47
49
|
}
|
|
@@ -3111,16 +3111,23 @@ class Dialog extends Controller {
|
|
|
3111
3111
|
}
|
|
3112
3112
|
|
|
3113
3113
|
class Tabs extends Controller {
|
|
3114
|
-
static targets = ["tab", "panel"];
|
|
3114
|
+
static targets = ["tab", "panel", "list"];
|
|
3115
3115
|
connect() {
|
|
3116
3116
|
const activeIndex = this.tabTargets.findIndex(
|
|
3117
3117
|
(tab) => tab.getAttribute("aria-selected") === "true"
|
|
3118
3118
|
);
|
|
3119
3119
|
this.activateTab(activeIndex >= 0 ? activeIndex : 0);
|
|
3120
3120
|
this.element.addEventListener("keydown", this.handleKeydown);
|
|
3121
|
+
if (this.hasListTarget) {
|
|
3122
|
+
this.updateOverflow();
|
|
3123
|
+
this.listTarget.addEventListener("scroll", this.updateOverflow);
|
|
3124
|
+
}
|
|
3121
3125
|
}
|
|
3122
3126
|
disconnect() {
|
|
3123
3127
|
this.element.removeEventListener("keydown", this.handleKeydown);
|
|
3128
|
+
if (this.hasListTarget) {
|
|
3129
|
+
this.listTarget.removeEventListener("scroll", this.updateOverflow);
|
|
3130
|
+
}
|
|
3124
3131
|
}
|
|
3125
3132
|
select(event) {
|
|
3126
3133
|
const tab = event.currentTarget;
|
|
@@ -3128,6 +3135,13 @@ class Tabs extends Controller {
|
|
|
3128
3135
|
if (index >= 0)
|
|
3129
3136
|
this.activateTab(index);
|
|
3130
3137
|
}
|
|
3138
|
+
updateOverflow = () => {
|
|
3139
|
+
if (!this.hasListTarget)
|
|
3140
|
+
return;
|
|
3141
|
+
const list = this.listTarget;
|
|
3142
|
+
list.classList.toggle("can-scroll-left", list.scrollLeft > 0);
|
|
3143
|
+
list.classList.toggle("can-scroll-right", list.scrollLeft < list.scrollWidth - list.clientWidth - 1);
|
|
3144
|
+
};
|
|
3131
3145
|
handleKeydown = (event) => {
|
|
3132
3146
|
const tabs = this.tabTargets;
|
|
3133
3147
|
if (tabs.length === 0)
|
|
@@ -3230,7 +3244,8 @@ class Carousel extends Controller {
|
|
|
3230
3244
|
static targets = ["track", "prev", "next", "dot"];
|
|
3231
3245
|
static values = {
|
|
3232
3246
|
wizard: { type: Boolean, default: false },
|
|
3233
|
-
autoplay: { type: Number, default: 0 }
|
|
3247
|
+
autoplay: { type: Number, default: 0 },
|
|
3248
|
+
loop: { type: Boolean, default: false }
|
|
3234
3249
|
};
|
|
3235
3250
|
observer = null;
|
|
3236
3251
|
_currentIndex = 0;
|
|
@@ -3266,10 +3281,21 @@ class Carousel extends Controller {
|
|
|
3266
3281
|
this.stopAutoplay();
|
|
3267
3282
|
}
|
|
3268
3283
|
next() {
|
|
3269
|
-
this.
|
|
3284
|
+
const atEnd = this._currentIndex >= this.slides.length - 1;
|
|
3285
|
+
if (this.loopValue && atEnd) {
|
|
3286
|
+
this.slides[0]?.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
|
|
3287
|
+
} else {
|
|
3288
|
+
this.trackTarget.scrollBy({ left: this.trackTarget.clientWidth, behavior: "smooth" });
|
|
3289
|
+
}
|
|
3270
3290
|
}
|
|
3271
3291
|
previous() {
|
|
3272
|
-
|
|
3292
|
+
const atStart = this._currentIndex <= 0;
|
|
3293
|
+
if (this.loopValue && atStart) {
|
|
3294
|
+
const last = this.slides[this.slides.length - 1];
|
|
3295
|
+
last?.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
|
|
3296
|
+
} else {
|
|
3297
|
+
this.trackTarget.scrollBy({ left: -this.trackTarget.clientWidth, behavior: "smooth" });
|
|
3298
|
+
}
|
|
3273
3299
|
}
|
|
3274
3300
|
goto(event) {
|
|
3275
3301
|
const button = event.currentTarget;
|
|
@@ -3436,11 +3462,11 @@ class Carousel extends Controller {
|
|
|
3436
3462
|
const atStart = track.scrollLeft <= 0;
|
|
3437
3463
|
const atEnd = track.scrollLeft >= track.scrollWidth - track.clientWidth - 1;
|
|
3438
3464
|
if (this.hasPrevTarget)
|
|
3439
|
-
this.prevTarget.classList.toggle("hide", atStart);
|
|
3465
|
+
this.prevTarget.classList.toggle("hide", atStart && !this.loopValue);
|
|
3440
3466
|
if (this.hasNextTarget) {
|
|
3441
3467
|
const atLastSlide = this._currentIndex >= this.slides.length - 1;
|
|
3442
3468
|
const frontierReached = this.wizardValue && this._currentIndex >= this._maxUnlocked;
|
|
3443
|
-
this.nextTarget.classList.toggle("hide", atEnd || atLastSlide || frontierReached);
|
|
3469
|
+
this.nextTarget.classList.toggle("hide", (atEnd || atLastSlide || frontierReached) && !this.loopValue);
|
|
3444
3470
|
}
|
|
3445
3471
|
if (this.wizardValue && this.hasDotTarget) {
|
|
3446
3472
|
this.dotTargets.forEach((dot, i) => {
|
|
@@ -4177,6 +4203,536 @@ class Autocomplete extends Controller {
|
|
|
4177
4203
|
}
|
|
4178
4204
|
}
|
|
4179
4205
|
|
|
4206
|
+
/*
|
|
4207
|
+
* Color Thief v2.0
|
|
4208
|
+
* by Lokesh Dhakar - http://www.lokeshdhakar.com
|
|
4209
|
+
*
|
|
4210
|
+
* Thanks
|
|
4211
|
+
* ------
|
|
4212
|
+
* Nick Rabinowitz - For creating quantize.js.
|
|
4213
|
+
* John Schulz - For clean up and optimization. @JFSIII
|
|
4214
|
+
* Nathan Spady - For adding drag and drop support to the demo page.
|
|
4215
|
+
*
|
|
4216
|
+
* License
|
|
4217
|
+
* -------
|
|
4218
|
+
* Copyright 2011, 2015 Lokesh Dhakar
|
|
4219
|
+
* Released under the MIT license
|
|
4220
|
+
* https://raw.githubusercontent.com/lokesh/color-thief/master/LICENSE
|
|
4221
|
+
*
|
|
4222
|
+
* @license
|
|
4223
|
+
*/
|
|
4224
|
+
const CanvasImage = function(image) {
|
|
4225
|
+
this.canvas = document.createElement("canvas");
|
|
4226
|
+
this.context = this.canvas.getContext("2d");
|
|
4227
|
+
document.body.appendChild(this.canvas);
|
|
4228
|
+
this.width = this.canvas.width = image.width;
|
|
4229
|
+
this.height = this.canvas.height = image.height;
|
|
4230
|
+
this.context.drawImage(image, 0, 0, this.width, this.height);
|
|
4231
|
+
};
|
|
4232
|
+
CanvasImage.prototype.clear = function() {
|
|
4233
|
+
this.context.clearRect(0, 0, this.width, this.height);
|
|
4234
|
+
};
|
|
4235
|
+
CanvasImage.prototype.update = function(imageData) {
|
|
4236
|
+
this.context.putImageData(imageData, 0, 0);
|
|
4237
|
+
};
|
|
4238
|
+
CanvasImage.prototype.getPixelCount = function() {
|
|
4239
|
+
return this.width * this.height;
|
|
4240
|
+
};
|
|
4241
|
+
CanvasImage.prototype.getImageData = function() {
|
|
4242
|
+
return this.context.getImageData(0, 0, this.width, this.height);
|
|
4243
|
+
};
|
|
4244
|
+
CanvasImage.prototype.removeCanvas = function() {
|
|
4245
|
+
this.canvas.parentNode.removeChild(this.canvas);
|
|
4246
|
+
};
|
|
4247
|
+
const ColorThief = function() {
|
|
4248
|
+
};
|
|
4249
|
+
ColorThief.prototype.getColor = function(sourceImage2, quality) {
|
|
4250
|
+
const palette = this.getPalette(sourceImage2, 5, quality);
|
|
4251
|
+
const dominantColor = palette[0];
|
|
4252
|
+
return dominantColor;
|
|
4253
|
+
};
|
|
4254
|
+
ColorThief.prototype.getPalette = function(sourceImage2, colorCount, quality) {
|
|
4255
|
+
if (typeof colorCount === "undefined" || colorCount < 2 || colorCount > 256) {
|
|
4256
|
+
colorCount = 10;
|
|
4257
|
+
}
|
|
4258
|
+
if (typeof quality === "undefined" || quality < 1) {
|
|
4259
|
+
quality = 10;
|
|
4260
|
+
}
|
|
4261
|
+
const image = new CanvasImage(sourceImage2);
|
|
4262
|
+
const imageData = image.getImageData();
|
|
4263
|
+
const pixels = imageData.data;
|
|
4264
|
+
const pixelCount = image.getPixelCount();
|
|
4265
|
+
const pixelArray = [];
|
|
4266
|
+
for (var i = 0, offset, r, g, b, a; i < pixelCount; i = i + quality) {
|
|
4267
|
+
offset = i * 4;
|
|
4268
|
+
r = pixels[offset + 0];
|
|
4269
|
+
g = pixels[offset + 1];
|
|
4270
|
+
b = pixels[offset + 2];
|
|
4271
|
+
a = pixels[offset + 3];
|
|
4272
|
+
if (a >= 125) {
|
|
4273
|
+
if (!(r > 250 && g > 250 && b > 250)) {
|
|
4274
|
+
pixelArray.push([r, g, b]);
|
|
4275
|
+
}
|
|
4276
|
+
}
|
|
4277
|
+
}
|
|
4278
|
+
const cmap = MMCQ.quantize(pixelArray, colorCount);
|
|
4279
|
+
const palette = cmap ? cmap.palette() : null;
|
|
4280
|
+
image.removeCanvas();
|
|
4281
|
+
return palette;
|
|
4282
|
+
};
|
|
4283
|
+
ColorThief.prototype.getColorFromUrl = function(imageUrl, callback, quality) {
|
|
4284
|
+
sourceImage = document.createElement("img");
|
|
4285
|
+
const thief = this;
|
|
4286
|
+
sourceImage.addEventListener("load", function() {
|
|
4287
|
+
const palette = thief.getPalette(sourceImage, 5, quality);
|
|
4288
|
+
const dominantColor = palette[0];
|
|
4289
|
+
callback(dominantColor, imageUrl);
|
|
4290
|
+
});
|
|
4291
|
+
sourceImage.src = imageUrl;
|
|
4292
|
+
};
|
|
4293
|
+
ColorThief.prototype.getImageData = function(imageUrl, callback) {
|
|
4294
|
+
xhr = new XMLHttpRequest();
|
|
4295
|
+
xhr.open("GET", imageUrl, true);
|
|
4296
|
+
xhr.responseType = "arraybuffer";
|
|
4297
|
+
xhr.onload = function(e) {
|
|
4298
|
+
if (this.status == 200) {
|
|
4299
|
+
uInt8Array = new Uint8Array(this.response);
|
|
4300
|
+
i = uInt8Array.length;
|
|
4301
|
+
binaryString = new Array(i);
|
|
4302
|
+
for (var i = 0; i < uInt8Array.length; i++) {
|
|
4303
|
+
binaryString[i] = String.fromCharCode(uInt8Array[i]);
|
|
4304
|
+
}
|
|
4305
|
+
data = binaryString.join("");
|
|
4306
|
+
base64 = window.btoa(data);
|
|
4307
|
+
callback("data:image/png;base64," + base64);
|
|
4308
|
+
}
|
|
4309
|
+
};
|
|
4310
|
+
xhr.send();
|
|
4311
|
+
};
|
|
4312
|
+
ColorThief.prototype.getColorAsync = function(imageUrl, callback, quality) {
|
|
4313
|
+
const thief = this;
|
|
4314
|
+
this.getImageData(imageUrl, function(imageData) {
|
|
4315
|
+
sourceImage = document.createElement("img");
|
|
4316
|
+
sourceImage.addEventListener("load", function() {
|
|
4317
|
+
const palette = thief.getPalette(sourceImage, 5, quality);
|
|
4318
|
+
const dominantColor = palette[0];
|
|
4319
|
+
callback(dominantColor, this);
|
|
4320
|
+
});
|
|
4321
|
+
sourceImage.src = imageData;
|
|
4322
|
+
});
|
|
4323
|
+
};
|
|
4324
|
+
/*!
|
|
4325
|
+
* quantize.js Copyright 2008 Nick Rabinowitz.
|
|
4326
|
+
* Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
|
|
4327
|
+
* @license
|
|
4328
|
+
*/
|
|
4329
|
+
/*!
|
|
4330
|
+
* Block below copied from Protovis: http://mbostock.github.com/protovis/
|
|
4331
|
+
* Copyright 2010 Stanford Visualization Group
|
|
4332
|
+
* Licensed under the BSD License: http://www.opensource.org/licenses/bsd-license.php
|
|
4333
|
+
* @license
|
|
4334
|
+
*/
|
|
4335
|
+
if (!pv) {
|
|
4336
|
+
var pv = {
|
|
4337
|
+
map: function(array, f) {
|
|
4338
|
+
const o = {};
|
|
4339
|
+
return f ? array.map(function(d, i) {
|
|
4340
|
+
o.index = i;
|
|
4341
|
+
return f.call(o, d);
|
|
4342
|
+
}) : array.slice();
|
|
4343
|
+
},
|
|
4344
|
+
naturalOrder: function(a, b) {
|
|
4345
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
4346
|
+
},
|
|
4347
|
+
sum: function(array, f) {
|
|
4348
|
+
const o = {};
|
|
4349
|
+
return array.reduce(f ? function(p, d, i) {
|
|
4350
|
+
o.index = i;
|
|
4351
|
+
return p + f.call(o, d);
|
|
4352
|
+
} : function(p, d) {
|
|
4353
|
+
return p + d;
|
|
4354
|
+
}, 0);
|
|
4355
|
+
},
|
|
4356
|
+
max: function(array, f) {
|
|
4357
|
+
return Math.max.apply(null, f ? pv.map(array, f) : array);
|
|
4358
|
+
}
|
|
4359
|
+
};
|
|
4360
|
+
}
|
|
4361
|
+
var MMCQ = function() {
|
|
4362
|
+
const sigbits = 5, rshift = 8 - sigbits, maxIterations = 1e3, fractByPopulations = 0.75;
|
|
4363
|
+
function getColorIndex(r, g, b) {
|
|
4364
|
+
return (r << 2 * sigbits) + (g << sigbits) + b;
|
|
4365
|
+
}
|
|
4366
|
+
function PQueue(comparator) {
|
|
4367
|
+
let contents = [], sorted = false;
|
|
4368
|
+
function sort() {
|
|
4369
|
+
contents.sort(comparator);
|
|
4370
|
+
sorted = true;
|
|
4371
|
+
}
|
|
4372
|
+
return {
|
|
4373
|
+
push: function(o) {
|
|
4374
|
+
contents.push(o);
|
|
4375
|
+
sorted = false;
|
|
4376
|
+
},
|
|
4377
|
+
peek: function(index) {
|
|
4378
|
+
if (!sorted)
|
|
4379
|
+
sort();
|
|
4380
|
+
if (index === void 0)
|
|
4381
|
+
index = contents.length - 1;
|
|
4382
|
+
return contents[index];
|
|
4383
|
+
},
|
|
4384
|
+
pop: function() {
|
|
4385
|
+
if (!sorted)
|
|
4386
|
+
sort();
|
|
4387
|
+
return contents.pop();
|
|
4388
|
+
},
|
|
4389
|
+
size: function() {
|
|
4390
|
+
return contents.length;
|
|
4391
|
+
},
|
|
4392
|
+
map: function(f) {
|
|
4393
|
+
return contents.map(f);
|
|
4394
|
+
},
|
|
4395
|
+
debug: function() {
|
|
4396
|
+
if (!sorted)
|
|
4397
|
+
sort();
|
|
4398
|
+
return contents;
|
|
4399
|
+
}
|
|
4400
|
+
};
|
|
4401
|
+
}
|
|
4402
|
+
function VBox(r1, r2, g1, g2, b1, b2, histo) {
|
|
4403
|
+
const vbox = this;
|
|
4404
|
+
vbox.r1 = r1;
|
|
4405
|
+
vbox.r2 = r2;
|
|
4406
|
+
vbox.g1 = g1;
|
|
4407
|
+
vbox.g2 = g2;
|
|
4408
|
+
vbox.b1 = b1;
|
|
4409
|
+
vbox.b2 = b2;
|
|
4410
|
+
vbox.histo = histo;
|
|
4411
|
+
}
|
|
4412
|
+
VBox.prototype = {
|
|
4413
|
+
volume: function(force) {
|
|
4414
|
+
const vbox = this;
|
|
4415
|
+
if (!vbox._volume || force) {
|
|
4416
|
+
vbox._volume = (vbox.r2 - vbox.r1 + 1) * (vbox.g2 - vbox.g1 + 1) * (vbox.b2 - vbox.b1 + 1);
|
|
4417
|
+
}
|
|
4418
|
+
return vbox._volume;
|
|
4419
|
+
},
|
|
4420
|
+
count: function(force) {
|
|
4421
|
+
const vbox = this, histo = vbox.histo;
|
|
4422
|
+
if (!vbox._count_set || force) {
|
|
4423
|
+
let npix = 0, index, i, j, k;
|
|
4424
|
+
for (i = vbox.r1; i <= vbox.r2; i++) {
|
|
4425
|
+
for (j = vbox.g1; j <= vbox.g2; j++) {
|
|
4426
|
+
for (k = vbox.b1; k <= vbox.b2; k++) {
|
|
4427
|
+
index = getColorIndex(i, j, k);
|
|
4428
|
+
npix += histo[index] || 0;
|
|
4429
|
+
}
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
vbox._count = npix;
|
|
4433
|
+
vbox._count_set = true;
|
|
4434
|
+
}
|
|
4435
|
+
return vbox._count;
|
|
4436
|
+
},
|
|
4437
|
+
copy: function() {
|
|
4438
|
+
const vbox = this;
|
|
4439
|
+
return new VBox(vbox.r1, vbox.r2, vbox.g1, vbox.g2, vbox.b1, vbox.b2, vbox.histo);
|
|
4440
|
+
},
|
|
4441
|
+
avg: function(force) {
|
|
4442
|
+
const vbox = this, histo = vbox.histo;
|
|
4443
|
+
if (!vbox._avg || force) {
|
|
4444
|
+
let ntot = 0, mult = 1 << 8 - sigbits, rsum = 0, gsum = 0, bsum = 0, hval, i, j, k, histoindex;
|
|
4445
|
+
for (i = vbox.r1; i <= vbox.r2; i++) {
|
|
4446
|
+
for (j = vbox.g1; j <= vbox.g2; j++) {
|
|
4447
|
+
for (k = vbox.b1; k <= vbox.b2; k++) {
|
|
4448
|
+
histoindex = getColorIndex(i, j, k);
|
|
4449
|
+
hval = histo[histoindex] || 0;
|
|
4450
|
+
ntot += hval;
|
|
4451
|
+
rsum += hval * (i + 0.5) * mult;
|
|
4452
|
+
gsum += hval * (j + 0.5) * mult;
|
|
4453
|
+
bsum += hval * (k + 0.5) * mult;
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
}
|
|
4457
|
+
if (ntot) {
|
|
4458
|
+
vbox._avg = [~~(rsum / ntot), ~~(gsum / ntot), ~~(bsum / ntot)];
|
|
4459
|
+
} else {
|
|
4460
|
+
vbox._avg = [
|
|
4461
|
+
~~(mult * (vbox.r1 + vbox.r2 + 1) / 2),
|
|
4462
|
+
~~(mult * (vbox.g1 + vbox.g2 + 1) / 2),
|
|
4463
|
+
~~(mult * (vbox.b1 + vbox.b2 + 1) / 2)
|
|
4464
|
+
];
|
|
4465
|
+
}
|
|
4466
|
+
}
|
|
4467
|
+
return vbox._avg;
|
|
4468
|
+
},
|
|
4469
|
+
contains: function(pixel) {
|
|
4470
|
+
const vbox = this, rval = pixel[0] >> rshift;
|
|
4471
|
+
gval = pixel[1] >> rshift;
|
|
4472
|
+
bval = pixel[2] >> rshift;
|
|
4473
|
+
return rval >= vbox.r1 && rval <= vbox.r2 && gval >= vbox.g1 && gval <= vbox.g2 && bval >= vbox.b1 && bval <= vbox.b2;
|
|
4474
|
+
}
|
|
4475
|
+
};
|
|
4476
|
+
function CMap() {
|
|
4477
|
+
this.vboxes = new PQueue(function(a, b) {
|
|
4478
|
+
return pv.naturalOrder(
|
|
4479
|
+
a.vbox.count() * a.vbox.volume(),
|
|
4480
|
+
b.vbox.count() * b.vbox.volume()
|
|
4481
|
+
);
|
|
4482
|
+
});
|
|
4483
|
+
}
|
|
4484
|
+
CMap.prototype = {
|
|
4485
|
+
push: function(vbox) {
|
|
4486
|
+
this.vboxes.push({
|
|
4487
|
+
vbox,
|
|
4488
|
+
color: vbox.avg()
|
|
4489
|
+
});
|
|
4490
|
+
},
|
|
4491
|
+
palette: function() {
|
|
4492
|
+
return this.vboxes.map(function(vb) {
|
|
4493
|
+
return vb.color;
|
|
4494
|
+
});
|
|
4495
|
+
},
|
|
4496
|
+
size: function() {
|
|
4497
|
+
return this.vboxes.size();
|
|
4498
|
+
},
|
|
4499
|
+
map: function(color) {
|
|
4500
|
+
const vboxes = this.vboxes;
|
|
4501
|
+
for (let i = 0; i < vboxes.size(); i++) {
|
|
4502
|
+
if (vboxes.peek(i).vbox.contains(color)) {
|
|
4503
|
+
return vboxes.peek(i).color;
|
|
4504
|
+
}
|
|
4505
|
+
}
|
|
4506
|
+
return this.nearest(color);
|
|
4507
|
+
},
|
|
4508
|
+
nearest: function(color) {
|
|
4509
|
+
let vboxes = this.vboxes, d1, d2, pColor;
|
|
4510
|
+
for (let i = 0; i < vboxes.size(); i++) {
|
|
4511
|
+
d2 = Math.sqrt(
|
|
4512
|
+
Math.pow(color[0] - vboxes.peek(i).color[0], 2) + Math.pow(color[1] - vboxes.peek(i).color[1], 2) + Math.pow(color[2] - vboxes.peek(i).color[2], 2)
|
|
4513
|
+
);
|
|
4514
|
+
if (d2 < d1 || d1 === void 0) {
|
|
4515
|
+
d1 = d2;
|
|
4516
|
+
pColor = vboxes.peek(i).color;
|
|
4517
|
+
}
|
|
4518
|
+
}
|
|
4519
|
+
return pColor;
|
|
4520
|
+
},
|
|
4521
|
+
forcebw: function() {
|
|
4522
|
+
const vboxes = this.vboxes;
|
|
4523
|
+
vboxes.sort(function(a, b) {
|
|
4524
|
+
return pv.naturalOrder(pv.sum(a.color), pv.sum(b.color));
|
|
4525
|
+
});
|
|
4526
|
+
const lowest = vboxes[0].color;
|
|
4527
|
+
if (lowest[0] < 5 && lowest[1] < 5 && lowest[2] < 5)
|
|
4528
|
+
vboxes[0].color = [0, 0, 0];
|
|
4529
|
+
const idx = vboxes.length - 1, highest = vboxes[idx].color;
|
|
4530
|
+
if (highest[0] > 251 && highest[1] > 251 && highest[2] > 251)
|
|
4531
|
+
vboxes[idx].color = [255, 255, 255];
|
|
4532
|
+
}
|
|
4533
|
+
};
|
|
4534
|
+
function getHisto(pixels) {
|
|
4535
|
+
let histosize = 1 << 3 * sigbits, histo = new Array(histosize), index, rval, gval2, bval2;
|
|
4536
|
+
pixels.forEach(function(pixel) {
|
|
4537
|
+
rval = pixel[0] >> rshift;
|
|
4538
|
+
gval2 = pixel[1] >> rshift;
|
|
4539
|
+
bval2 = pixel[2] >> rshift;
|
|
4540
|
+
index = getColorIndex(rval, gval2, bval2);
|
|
4541
|
+
histo[index] = (histo[index] || 0) + 1;
|
|
4542
|
+
});
|
|
4543
|
+
return histo;
|
|
4544
|
+
}
|
|
4545
|
+
function vboxFromPixels(pixels, histo) {
|
|
4546
|
+
let rmin = 1e6, rmax = 0, gmin = 1e6, gmax = 0, bmin = 1e6, bmax = 0, rval, gval2, bval2;
|
|
4547
|
+
pixels.forEach(function(pixel) {
|
|
4548
|
+
rval = pixel[0] >> rshift;
|
|
4549
|
+
gval2 = pixel[1] >> rshift;
|
|
4550
|
+
bval2 = pixel[2] >> rshift;
|
|
4551
|
+
if (rval < rmin)
|
|
4552
|
+
rmin = rval;
|
|
4553
|
+
else if (rval > rmax)
|
|
4554
|
+
rmax = rval;
|
|
4555
|
+
if (gval2 < gmin)
|
|
4556
|
+
gmin = gval2;
|
|
4557
|
+
else if (gval2 > gmax)
|
|
4558
|
+
gmax = gval2;
|
|
4559
|
+
if (bval2 < bmin)
|
|
4560
|
+
bmin = bval2;
|
|
4561
|
+
else if (bval2 > bmax)
|
|
4562
|
+
bmax = bval2;
|
|
4563
|
+
});
|
|
4564
|
+
return new VBox(rmin, rmax, gmin, gmax, bmin, bmax, histo);
|
|
4565
|
+
}
|
|
4566
|
+
function medianCutApply(histo, vbox) {
|
|
4567
|
+
if (!vbox.count())
|
|
4568
|
+
return;
|
|
4569
|
+
const rw = vbox.r2 - vbox.r1 + 1, gw = vbox.g2 - vbox.g1 + 1, bw = vbox.b2 - vbox.b1 + 1, maxw = pv.max([rw, gw, bw]);
|
|
4570
|
+
if (vbox.count() == 1) {
|
|
4571
|
+
return [vbox.copy()];
|
|
4572
|
+
}
|
|
4573
|
+
let total = 0, partialsum = [], lookaheadsum = [], i, j, k, sum, index;
|
|
4574
|
+
if (maxw == rw) {
|
|
4575
|
+
for (i = vbox.r1; i <= vbox.r2; i++) {
|
|
4576
|
+
sum = 0;
|
|
4577
|
+
for (j = vbox.g1; j <= vbox.g2; j++) {
|
|
4578
|
+
for (k = vbox.b1; k <= vbox.b2; k++) {
|
|
4579
|
+
index = getColorIndex(i, j, k);
|
|
4580
|
+
sum += histo[index] || 0;
|
|
4581
|
+
}
|
|
4582
|
+
}
|
|
4583
|
+
total += sum;
|
|
4584
|
+
partialsum[i] = total;
|
|
4585
|
+
}
|
|
4586
|
+
} else if (maxw == gw) {
|
|
4587
|
+
for (i = vbox.g1; i <= vbox.g2; i++) {
|
|
4588
|
+
sum = 0;
|
|
4589
|
+
for (j = vbox.r1; j <= vbox.r2; j++) {
|
|
4590
|
+
for (k = vbox.b1; k <= vbox.b2; k++) {
|
|
4591
|
+
index = getColorIndex(j, i, k);
|
|
4592
|
+
sum += histo[index] || 0;
|
|
4593
|
+
}
|
|
4594
|
+
}
|
|
4595
|
+
total += sum;
|
|
4596
|
+
partialsum[i] = total;
|
|
4597
|
+
}
|
|
4598
|
+
} else {
|
|
4599
|
+
for (i = vbox.b1; i <= vbox.b2; i++) {
|
|
4600
|
+
sum = 0;
|
|
4601
|
+
for (j = vbox.r1; j <= vbox.r2; j++) {
|
|
4602
|
+
for (k = vbox.g1; k <= vbox.g2; k++) {
|
|
4603
|
+
index = getColorIndex(j, k, i);
|
|
4604
|
+
sum += histo[index] || 0;
|
|
4605
|
+
}
|
|
4606
|
+
}
|
|
4607
|
+
total += sum;
|
|
4608
|
+
partialsum[i] = total;
|
|
4609
|
+
}
|
|
4610
|
+
}
|
|
4611
|
+
partialsum.forEach(function(d, i2) {
|
|
4612
|
+
lookaheadsum[i2] = total - d;
|
|
4613
|
+
});
|
|
4614
|
+
function doCut(color) {
|
|
4615
|
+
let dim1 = color + "1", dim2 = color + "2", left, right, vbox1, vbox2, d2, count2 = 0;
|
|
4616
|
+
for (i = vbox[dim1]; i <= vbox[dim2]; i++) {
|
|
4617
|
+
if (partialsum[i] > total / 2) {
|
|
4618
|
+
vbox1 = vbox.copy();
|
|
4619
|
+
vbox2 = vbox.copy();
|
|
4620
|
+
left = i - vbox[dim1];
|
|
4621
|
+
right = vbox[dim2] - i;
|
|
4622
|
+
if (left <= right)
|
|
4623
|
+
d2 = Math.min(vbox[dim2] - 1, ~~(i + right / 2));
|
|
4624
|
+
else
|
|
4625
|
+
d2 = Math.max(vbox[dim1], ~~(i - 1 - left / 2));
|
|
4626
|
+
while (!partialsum[d2])
|
|
4627
|
+
d2++;
|
|
4628
|
+
count2 = lookaheadsum[d2];
|
|
4629
|
+
while (!count2 && partialsum[d2 - 1])
|
|
4630
|
+
count2 = lookaheadsum[--d2];
|
|
4631
|
+
vbox1[dim2] = d2;
|
|
4632
|
+
vbox2[dim1] = vbox1[dim2] + 1;
|
|
4633
|
+
return [vbox1, vbox2];
|
|
4634
|
+
}
|
|
4635
|
+
}
|
|
4636
|
+
}
|
|
4637
|
+
return maxw == rw ? doCut("r") : maxw == gw ? doCut("g") : doCut("b");
|
|
4638
|
+
}
|
|
4639
|
+
function quantize(pixels, maxcolors) {
|
|
4640
|
+
if (!pixels.length || maxcolors < 2 || maxcolors > 256) {
|
|
4641
|
+
return false;
|
|
4642
|
+
}
|
|
4643
|
+
const histo = getHisto(pixels);
|
|
4644
|
+
histo.forEach(function() {
|
|
4645
|
+
});
|
|
4646
|
+
const vbox = vboxFromPixels(pixels, histo), pq = new PQueue(function(a, b) {
|
|
4647
|
+
return pv.naturalOrder(a.count(), b.count());
|
|
4648
|
+
});
|
|
4649
|
+
pq.push(vbox);
|
|
4650
|
+
function iter(lh, target) {
|
|
4651
|
+
let ncolors = 1, niters = 0, vbox2;
|
|
4652
|
+
while (niters < maxIterations) {
|
|
4653
|
+
vbox2 = lh.pop();
|
|
4654
|
+
if (!vbox2.count()) {
|
|
4655
|
+
lh.push(vbox2);
|
|
4656
|
+
niters++;
|
|
4657
|
+
continue;
|
|
4658
|
+
}
|
|
4659
|
+
const vboxes = medianCutApply(histo, vbox2), vbox1 = vboxes[0], vbox22 = vboxes[1];
|
|
4660
|
+
if (!vbox1) {
|
|
4661
|
+
return;
|
|
4662
|
+
}
|
|
4663
|
+
lh.push(vbox1);
|
|
4664
|
+
if (vbox22) {
|
|
4665
|
+
lh.push(vbox22);
|
|
4666
|
+
ncolors++;
|
|
4667
|
+
}
|
|
4668
|
+
if (ncolors >= target)
|
|
4669
|
+
return;
|
|
4670
|
+
if (niters++ > maxIterations) {
|
|
4671
|
+
return;
|
|
4672
|
+
}
|
|
4673
|
+
}
|
|
4674
|
+
}
|
|
4675
|
+
iter(pq, fractByPopulations * maxcolors);
|
|
4676
|
+
const pq2 = new PQueue(function(a, b) {
|
|
4677
|
+
return pv.naturalOrder(a.count() * a.volume(), b.count() * b.volume());
|
|
4678
|
+
});
|
|
4679
|
+
while (pq.size()) {
|
|
4680
|
+
pq2.push(pq.pop());
|
|
4681
|
+
}
|
|
4682
|
+
iter(pq2, maxcolors - pq2.size());
|
|
4683
|
+
const cmap = new CMap();
|
|
4684
|
+
while (pq2.size()) {
|
|
4685
|
+
cmap.push(pq2.pop());
|
|
4686
|
+
}
|
|
4687
|
+
return cmap;
|
|
4688
|
+
}
|
|
4689
|
+
return {
|
|
4690
|
+
quantize
|
|
4691
|
+
};
|
|
4692
|
+
}();
|
|
4693
|
+
|
|
4694
|
+
class Image extends Controller {
|
|
4695
|
+
static targets = ["dialog"];
|
|
4696
|
+
static values = { poster: String };
|
|
4697
|
+
connect() {
|
|
4698
|
+
this.extractColor();
|
|
4699
|
+
}
|
|
4700
|
+
extractColor() {
|
|
4701
|
+
if (!this.hasDialogTarget)
|
|
4702
|
+
return;
|
|
4703
|
+
const mainImg = this.element.querySelector("img.midwest-image-main");
|
|
4704
|
+
const colorSource = this.posterValue || mainImg?.src;
|
|
4705
|
+
if (!colorSource)
|
|
4706
|
+
return;
|
|
4707
|
+
const sample = new window.Image(80, 80);
|
|
4708
|
+
sample.crossOrigin = "Anonymous";
|
|
4709
|
+
sample.addEventListener("load", () => {
|
|
4710
|
+
try {
|
|
4711
|
+
const [r, g, b] = new ColorThief().getColor(sample);
|
|
4712
|
+
this.dialogTarget.style.setProperty("--image-dominant-color", `${r} ${g} ${b}`);
|
|
4713
|
+
} catch {
|
|
4714
|
+
}
|
|
4715
|
+
});
|
|
4716
|
+
sample.src = colorSource;
|
|
4717
|
+
}
|
|
4718
|
+
zoom() {
|
|
4719
|
+
if (this.hasDialogTarget) {
|
|
4720
|
+
this.dialogTarget.showModal();
|
|
4721
|
+
}
|
|
4722
|
+
}
|
|
4723
|
+
close() {
|
|
4724
|
+
if (this.hasDialogTarget) {
|
|
4725
|
+
this.dialogTarget.close();
|
|
4726
|
+
}
|
|
4727
|
+
}
|
|
4728
|
+
// Close when clicking the backdrop (outside the dialog content).
|
|
4729
|
+
backdropClose(event) {
|
|
4730
|
+
if (event.target === this.dialogTarget) {
|
|
4731
|
+
this.dialogTarget.close();
|
|
4732
|
+
}
|
|
4733
|
+
}
|
|
4734
|
+
}
|
|
4735
|
+
|
|
4180
4736
|
function registerMidwestControllers(application) {
|
|
4181
4737
|
application.register("midwest-card", Card);
|
|
4182
4738
|
application.register("midwest-banner", Banner);
|
|
@@ -4198,6 +4754,7 @@ function registerMidwestControllers(application) {
|
|
|
4198
4754
|
application.register("midwest-range", Range);
|
|
4199
4755
|
application.register("midwest-rating", Rating);
|
|
4200
4756
|
application.register("midwest-autocomplete", Autocomplete);
|
|
4757
|
+
application.register("midwest-image", Image);
|
|
4201
4758
|
}
|
|
4202
4759
|
|
|
4203
4760
|
export { Banner, Card, Chart, CountdownTimer, registerMidwestControllers };
|