Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@behance/helicropter

Package Overview
Dependencies
Maintainers
48
Versions
33
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@behance/helicropter - npm Package Compare versions

Comparing version 15.5.5 to 15.6.0

4

demo/index.js

@@ -30,4 +30,4 @@ import $ from 'jquery';

},
viewportRatio: 'static',
allowTransparency: false,
viewportRatio: 'dynamic',
allowTransparency: true,
// uploadTitle: 'Upload a new cover image',

@@ -34,0 +34,0 @@ // uploadSubtitle: 'This will not affect your Behance cover image',

{
"name": "@behance/helicropter",
"version": "15.5.5",
"version": "15.6.0",
"description": "My helicropter goes \"whosh whosh whosh\"",

@@ -5,0 +5,0 @@ "main": "src/js/index.js",

@@ -18,17 +18,24 @@ import View from '@behance/beff/View';

this._$canvas = this.$view.find('.js-cropper-canvas');
this._$canvas.prop({
this.canvasCss = {
width: this._model.canvasWidth,
height: this._model.canvasHeight,
});
};
const canvasContainerClass = 'js-canvas-container';
this._$canvas.prop(this.canvasCss);
this.canvasOrder = ['background', 'foreground'];
const containerClass = 'js-canvas-container';
this._canvas = new fabric.Canvas(this._$canvas[0], {
selection: false,
containerClass: canvasContainerClass,
containerClass,
});
this.$canvasContainer = this.$view.find(`.${canvasContainerClass}`);
this.$cropperCanvas = this.$view.find('.js-cropper-canvas');
this.$canvasContainer.css('transform-origin', 'left top');
this.$canvasContainer = this.$view.find(`.${containerClass}`);
this.$canvasContainer.css({
transformOrigin: 'left top',
zIndex: this.canvasOrder.indexOf('foreground'),
});

@@ -54,4 +61,2 @@ // IMPORTANT: Using undocumented Fabric.js API here to force retina-like behavior

this._createTransparencyBackground();
if (this._model.viewportRatio === 'static') {

@@ -76,3 +81,5 @@ this._createStaticCropArea();

'scale-view'({ scale }) {
this._scaleView({ scale });
this.scale = scale;
this._scaleView({ $el: this.$canvasContainer, scale });
this._scaleView({ $el: this.$backgroundContainer, scale });
},

@@ -85,2 +92,4 @@

this._createBackground().then(() => this.trigger('background-loaded'));
this.trigger('cropper-set-image');

@@ -155,5 +164,5 @@ },

return {
x: Math.max(0, (this._getImageProp('left') * -1) + this._getCropAreaProp('left')),
y: Math.max(0, (this._getImageProp('top') * -1) + this._getCropAreaProp('top')),
const retVal = {
x: this._getImageProp('left') * -1 + this._getCropAreaProp('left'),
y: this._getImageProp('top') * -1 + this._getCropAreaProp('top'),
width: Math.max(1, this._cropArea.width),

@@ -163,2 +172,7 @@ height: Math.max(1, this._cropArea.height),

};
return Object.assign({}, retVal, {
x: this._model.allowLetterboxing ? retVal.x : Math.max(0, retVal.x),
y: this._model.allowLetterboxing ? retVal.y : Math.max(0, retVal.y),
});
},

@@ -170,4 +184,2 @@

const { x, y, width, height, scale } = this.getCropData();
const nativeWidth = this._getImageProp('width');
const nativeHeight = this._getImageProp('height');

@@ -181,3 +193,22 @@ const scaledValues = {

const reductionRatio = this._getReductionRatio(scaledValues);
scaledValues.x = Math.floor(scaledValues.x * reductionRatio);
scaledValues.y = Math.floor(scaledValues.y * reductionRatio);
scaledValues.width = Math.floor(scaledValues.width * reductionRatio);
scaledValues.height = Math.floor(scaledValues.height * reductionRatio);
return scaledValues;
},
_getReductionRatio(scaledValues) {
let reductionRatio = 1;
if (this._model.allowLetterboxing) {
return reductionRatio;
}
const nativeWidth = this._getImageProp('width');
const nativeHeight = this._getImageProp('height');
if (scaledValues.width > nativeWidth) {

@@ -190,12 +221,22 @@ reductionRatio = nativeWidth / scaledValues.width;

scaledValues.x = Math.floor(scaledValues.x * reductionRatio);
scaledValues.y = Math.floor(scaledValues.y * reductionRatio);
scaledValues.width = Math.floor(scaledValues.width * reductionRatio);
scaledValues.height = Math.floor(scaledValues.height * reductionRatio);
return reductionRatio;
},
return scaledValues;
_createBackground() {
switch (this._model.backgroundType) {
case 'solid':
return this._createSolidBackground();
case 'image':
return this._createBlurryImageBackground();
default:
return this._createTransparencyBackground();
}
},
_scaleView({ scale }) {
this.$canvasContainer.css({
_scaleView({ $el, scale }) {
if (!$el || !$el.length) {
return;
}
$el.css({
transform: `scale(${scale})`,

@@ -205,3 +246,3 @@ });

requestAnimationFrame(() => {
const boundRect = this.$cropperCanvas[0].getBoundingClientRect();
const boundRect = this._$canvas[0].getBoundingClientRect();
let width = boundRect.width;

@@ -211,7 +252,7 @@ let height = boundRect.height;

if (!boundRect.width || !boundRect.height) {
width = Number(this.$cropperCanvas.width()) * scale;
height = Number(this.$cropperCanvas.height()) * scale;
width = Number(this._$canvas.width()) * scale;
height = Number(this._$canvas.height()) * scale;
}
this.$canvasContainer.css({
$el.css({
width,

@@ -240,2 +281,85 @@ height,

_createBlurryImageBackground() {
if (!this._model.image) {
return;
}
const containerClass = 'js-background-canvas-container';
const canvasClass = 'js-background-canvas';
const foregroundContainerClass = this._canvas.containerClass;
this.$view.find(`.${foregroundContainerClass}`).after(`<canvas class="${canvasClass}"></canvas>`);
const $backgroundCanvas = this.$view.find(`.${canvasClass}`);
$backgroundCanvas.prop(this.canvasCss);
this._backgroundCanvas = new fabric.Canvas($backgroundCanvas[0], {
selection: false,
containerClass,
});
this.$backgroundContainer = this.$view.find(`.${containerClass}`);
this.$backgroundContainer.css({
position: 'absolute',
zIndex: this.canvasOrder.indexOf('background'),
left: 0,
top: 0,
transformOrigin: 'left top',
});
return this._loadImage(this._model.image)
.then((image) => {
const backgroundImage = new fabric.Image(image, {
left: 0,
top: 0,
originX: 'left',
originY: 'top',
selectable: false,
hasBorders: false,
hasControls: false,
});
this._backgroundCanvas.add(backgroundImage);
backgroundImage.canvas.contextContainer.filter = 'blur(70px) brightness(.8)';
const isLandscape = backgroundImage.width > backgroundImage.height;
if (isLandscape) {
backgroundImage.scaleToHeight(this._canvas.height);
}
else {
backgroundImage.scaleToWidth(this._canvas.width);
}
backgroundImage.sendToBack();
backgroundImage.center();
this._scaleView({ $el: this.$backgroundContainer, scale: this.scale });
});
},
_createSolidBackground() {
return new Promise(resolve => {
const solidRect = new fabric.Rect({
left: 0,
top: 0,
width: this._model.canvasWidth,
height: this._model.canvasHeight,
fill: this._model.backgroundHex,
selectable: false,
evented: false,
hasBorders: false,
hasControls: false,
});
this._canvas.add(solidRect);
solidRect.sendToBack();
resolve();
});
},
_createTransparencyBackground() {

@@ -293,3 +417,4 @@ return this._loadImage(transparencyImage)

this._image.scale(normalizedCoordinates.scale).setCoords();
this._scaleImage(normalizedCoordinates.scale);
this._image.setCoords();
this._image.center();

@@ -384,2 +509,18 @@

_lockVerticalPan(imageTop) {
if (!this._model.allowLetterboxing) {
return;
}
this._image.lockMovementY = imageTop >= 0;
},
_lockHorizontalPan(imageLeft) {
if (!this._model.allowLetterboxing) {
return;
}
this._image.lockMovementX = imageLeft >= 0;
},
_scaleImage(scaleValue) {

@@ -392,2 +533,3 @@ if (!scaleValue) { return; }

};
const previousCentroid = {

@@ -409,6 +551,11 @@ left: (this._image.get('left') * -1) + this._cropArea.get('left') + (this._cropArea.getWidth() / 2),

this._image.set('left', this._image.get('left') + (previousCentroid.left - postCentroid.left));
this._image.set('top', this._image.get('top') + (previousCentroid.top - postCentroid.top));
const imageTop = this._image.get('top') + (previousCentroid.top - postCentroid.top);
const imageLeft = this._image.get('left') + (previousCentroid.left - postCentroid.left);
this._image.set('left', imageLeft);
this._image.set('top', imageTop);
this._image.setCoords();
this._lockVerticalPan(imageTop);
this._lockHorizontalPan(imageLeft);
this._checkImageBounds();

@@ -415,0 +562,0 @@

@@ -43,4 +43,7 @@ import extend from '@behance/nbd/util/extend';

allowTransparency: this._model.get('allowTransparency'),
allowLetterboxing: this._model.get('allowLetterboxing'),
previewMode: this._model.get('previewMode'),
blurryImageWarningText: this._model.get('blurryImageWarningText'),
backgroundHex: this._model.get('backgroundHex'),
backgroundType: this._model.get('backgroundType'),
});

@@ -47,0 +50,0 @@

import CroppingArea from 'CroppingArea';
import images from '../fixtures/images';

@@ -17,2 +18,16 @@ function createCroppingArea($el, data = {}) {

};
this.loadImage = (model) => {
return new Promise(resolve => {
this.croppingArea = createCroppingArea(this.$el, {
viewportRatio: 'static',
cropWidth: 500,
cropHeight: 500,
image: images.flower,
...model,
});
this.croppingArea.on('image-loaded', resolve);
});
};
});

@@ -64,3 +79,3 @@

const scale = .5;
this.croppingArea._scaleView({ scale });
this.croppingArea._scaleView({ $el: this.croppingArea.$canvasContainer, scale });

@@ -74,2 +89,116 @@ this.waitAFrame().then(() => {

describe('allowLetterboxing', function() {
it('locks vertical pan when it is true and there is no room to pan vertically', function(done) {
this.loadImage({ allowLetterboxing: true }).then(() => {
spyOn(this.croppingArea._cropArea, 'get').and.callFake((arg) => {
return {
top: 100,
}[arg];
});
this.croppingArea.trigger('scale', .5);
expect(this.croppingArea._image.lockMovementY).toEqual(true);
done();
});
});
it('unlocks vertical pan when it is true and there is room to pan vertically', function(done) {
this.loadImage({ allowLetterboxing: true }).then(() => {
spyOn(this.croppingArea._cropArea, 'get').and.callFake((arg) => {
return {
top: -100,
}[arg];
});
this.croppingArea.trigger('scale', .5);
expect(this.croppingArea._image.lockMovementY).toEqual(false);
done();
});
});
it('locks horizontal pan when it is true and there is no room to pan horizontally', function(done) {
this.loadImage({ allowLetterboxing: true }).then(() => {
spyOn(this.croppingArea._cropArea, 'get').and.callFake((arg) => {
return {
left: 500,
}[arg];
});
this.croppingArea.trigger('scale', .5);
expect(this.croppingArea._image.lockMovementX).toEqual(true);
done();
});
});
it('unlocks horizontal pan when it is true and there is room to pan horizontally', function(done) {
this.loadImage({ allowLetterboxing: true }).then(() => {
spyOn(this.croppingArea._cropArea, 'get').and.callFake((arg) => {
return {
left: -500,
}[arg];
});
this.croppingArea.trigger('scale', .5);
expect(this.croppingArea._image.lockMovementX).toEqual(false);
done();
});
});
});
describe('backgroundType', function() {
beforeEach(function() {
this.createCroppingAreaWithBackground = (backgroundType, data = {}) => {
return new Promise(resolve => {
this.croppingArea = createCroppingArea(this.$el, {
backgroundType,
...data,
});
spyOn(this.croppingArea, '_createSolidBackground').and.callThrough();
spyOn(this.croppingArea, '_createTransparencyBackground').and.callThrough();
this.croppingArea.trigger('set-image', images.flower, {});
this.croppingArea.on('background-loaded', resolve);
});
};
});
it('generates image background when it is "image"', function(done) {
this.createCroppingAreaWithBackground('image').then(() => {
expect(this.croppingArea._backgroundCanvas).toExist();
expect(this.croppingArea._backgroundCanvas.contextContainer.filter).toEqual('blur(70px) brightness(.8)');
done();
});
});
it('generates solid color background when it is "solid"', function(done) {
const backgroundHex = '#000000';
this.createCroppingAreaWithBackground('solid', {
backgroundHex,
canvasWidth: 100,
canvasHeight: 100,
}).then(() => {
expect(this.croppingArea._createSolidBackground).toHaveBeenCalled();
done();
});
});
it('generates transparency background when it is not set', function(done) {
this.createCroppingAreaWithBackground(null).then(() => {
expect(this.croppingArea._createTransparencyBackground).toHaveBeenCalled();
done();
});
});
});
describe('#disable', function() {

@@ -197,5 +326,59 @@ beforeEach(function() {

this.cropWidth = 900;
this.cropHeight = 1000;
this.expectDimensionsToNotReduceForImage = ({ width, height }) => {
return new Promise(resolve => {
this.croppingArea = createCroppingArea(this.$el, {
viewportRatio: 'static',
cropWidth: this.cropWidth,
cropHeight: this.cropHeight,
allowLetterboxing: true,
image: images.flower,
});
spyOn(this.croppingArea, '_getImageProp').and.callFake((prop) => {
return {
left: 0,
top: 0,
width,
height,
}[prop];
});
this.croppingArea.on('image-loaded', () => {
const crop = this.croppingArea.getCropData();
const expected = {
x: Math.floor(crop.x / crop.scale),
y: Math.floor(crop.y / crop.scale),
width: Math.floor(crop.width / crop.scale),
height: Math.floor(crop.height / crop.scale),
};
const dimensions = this.croppingArea.getDimensions();
expect(dimensions).toEqual(expected);
resolve();
});
});
};
this.croppingArea._image = { getScaleX: () => 0.5 };
});
it('returns non-reduces values for wide images when allowLetterboxing is true', function(done) {
this.expectDimensionsToNotReduceForImage({
width: this.cropWidth * 5,
height: this.cropHeight / 5,
}).then(done);
});
it('returns non-reduces values for tall images when allowLetterboxing is true', function(done) {
this.expectDimensionsToNotReduceForImage({
width: this.cropWidth / 5,
height: this.cropHeight * 5,
}).then(done);
});
it('returns undefined if no image is defined', function() {

@@ -202,0 +385,0 @@ this.croppingArea._image = null;

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc