🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
Book a DemoInstallSign in
Socket

altpro

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

altpro - npm Package Compare versions

Comparing version

to
0.0.1

lib/matrix2d.js

183

lib/altpro.js

@@ -0,4 +1,185 @@

const matrix2d = require('./matrix2d');
module.exports = altpro;
function altpro() {
function prepare(data) {
return data.reduce((r, { elevation, distance }) => {
if (elevation < r.minElevation) {
r.minElevation = elevation;
}
if (elevation > r.maxElevation) {
r.maxElevation = elevation;
}
r.totalDistance += distance;
r.items.push({ elevation, distance: r.totalDistance });
return r;
}, {
items: [],
totalDistance: 0,
minElevation: 0,
maxElevation: 0
});
}
function initMatrix({ w, h }, { x, y, min }) {
const horizontalPadding = 0;
const verticalPadding = 15;
w -= 2 * horizontalPadding;
h -= 2 * verticalPadding;
const horizontalScaling = w / x;
const verticalScaling = h / y;
return matrix2d()
.translate(horizontalPadding, verticalPadding)
.scale(horizontalScaling, -verticalScaling)
.translate(0, -(y + min));
}
function drawPath(ctx, items) {
ctx.beginPath();
const first = items[0];
const last = items[items.length - 1];
ctx.moveTo(0, first.elevation);
for(let i = 1; i < items.length; i++) {
const { elevation, distance } = items[i];
ctx.lineTo(distance, elevation);
}
ctx.stroke();
ctx.lineTo(last.distance, 0);
ctx.lineTo(0, 0);
ctx.closePath();
ctx.fill();
}
function drawSelected(ctx, { distance: d1, elevation: e1 }, { distance: d2, elevation: e2 }) {
ctx.beginPath();
ctx.moveTo(d1, 0);
ctx.lineTo(d1, e1);
ctx.lineTo(d2, e2);
ctx.lineTo(d2, 0);
ctx.closePath();
ctx.fill();
}
function clear(ctx, { w, h }) {
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, w, h);
ctx.restore();
}
function createCanvas(parent) {
function canvas(wrapper, w, h) {
const c = document.createElement('canvas');
c.style.position = 'absolute';
c.style.left = 0;
c.style.height = 0;
c.style.width = '100%';
c.style.height = '100%';
c.width = w;
c.height = h;
wrapper.appendChild(c);
return c;
}
const wrapper = document.createElement('div');
wrapper.style.position = 'relative';
wrapper.style.width = '100%';
wrapper.style.height = '100%';
parent.appendChild(wrapper);
const { clientWidth: w, clientHeight: h } = wrapper;
const bg = canvas(wrapper, w, h);
const fg = canvas(wrapper, w, h);
return { bg, fg, w, h };
}
function altpro(parent, data, opts = {}) {
const {
fill = 'chartreuse',
stroke = 'black',
selectedFill = 'orange'
} = opts;
const {
minElevation,
maxElevation,
totalDistance,
items
} = prepare(data);
const extent = {
x: totalDistance,
y: maxElevation - minElevation,
min: minElevation
};
const { bg, fg, w, h } = createCanvas(parent);
const ctx = bg.getContext('2d');
ctx.strokeStyle = stroke;
ctx.fillStyle = fill;
const transformMatric = initMatrix({ w, h }, extent);
const invertedMatrix = transformMatric.clone().invert();
transformMatric.apply(ctx);
drawPath(ctx, items);
const fgCtx = fg.getContext('2d');
fgCtx.fillStyle = selectedFill;
fgCtx.lineWidth = 3;
transformMatric.apply(fgCtx);
fg.addEventListener('mousemove', onmousemove);
fg.removeEventListener('mouseleve', onmouseleave);
return {
select,
destroy
};
function destroy() {
fg.removeEventListener('mousemove', onmousemove);
fg.removeEventListener('mouseleve', onmouseleave);
parent.innerHTML = '';
}
function onmousemove({ clientX, clientY, target }) {
const rect = target.getBoundingClientRect();
let index = itemIndexFromPoint([
clientX - rect.left,
clientY - rect.top
]);
select(index);
}
function onmouseleave() {
clear(fgCtx, { w, h });
}
function itemIndexFromPoint(point) {
const [ distance ] = unproject(point);
return items.findIndex(item => distance < item.distance);
}
function unproject(point) {
return invertedMatrix.project(point);
}
function select(index) {
if (index < 1 || index >= items.length) {
return;
}
clear(fgCtx, { w, h });
drawSelected(fgCtx, items[index - 1], items[index]);
}
}

11

package.json
{
"name": "altpro",
"version": "0.0.0",
"version": "0.0.1",
"description": "Elevation profile widget.",

@@ -19,5 +19,6 @@ "author": {

"devDependencies": {
"jshint": "^2.9.7",
"mocha": "^5.2.0",
"should": "^13.2.3"
"browserify": "~16",
"jshint": "~2",
"mocha": "~5",
"should": "~13"
},

@@ -31,2 +32,2 @@ "scripts": {

]
}
}

@@ -8,3 +8,3 @@ [![NPM version][npm-image]][npm-url]

Elevation profile widget.
Elevation profile widget. See demo [here][demo].

@@ -20,7 +20,40 @@ ## Install

```js
var altpro = require('altpro');
altpro('Rainbow');
const data = [
{ elevation: 10, distance: 0 },
{ elevation: 15, distance: 10 },
{ elevation: 25, distance: 10 },
// etc.
];
const altpro = require('altpro');
const container = document.querySelector('.altitude-profile-container');
altpro(container, data);
```
## API
### `altpro(parent, data, options)`
Creates new widget inside of `parent`. `parent` element has to exist, be visible and have desired size.
- `data` is an `Array` of items with `elevation` and `distance` properties. All other properties are
ignored, and `data` is not changed by `altpro`. `distance` means - distance from previous items.
The following `options` can be passed:
- `fill` - [fillStyle] for main graph background
- `stroke` - [strokeStyle] for line at the top of the graph
- `selectedFill` - [fillStyle] for the selected item
### `altpro.select(index)`
Selects `index` element of data.
### `altpro.destroy()`
Removes altpro widget from DOM, unbinds all listeners.
## License

@@ -30,2 +63,7 @@

[fillStyle]: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/fillStyle
[strokeStyle]: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/strokeStyle
[demo]: https://pirxpilot.github.io/altpro
[npm-image]: https://img.shields.io/npm/v/altpro.svg

@@ -32,0 +70,0 @@ [npm-url]: https://npmjs.org/package/altpro