Raphael drag clone onDragOver - raphael

Currently I drag a clone of a draggable Raphael element by using element.clone() in the dragStart function and moving the clone in the dragMove function (removing it in the dragStop function).
This raises an issue with the onDragOver function for the draggable element since most of the time the clone throws the corresponding event instead of the targeted one.
Some code:
dragStart = function() {
var s = this, c = s.clone();
s.data('clone', c);
c.ox = c.attr('cx');
c.oy = c.attr('cy');
};
dragMove = function(dx, dy) {
var s = this, c = s.data('clone');
c.attr({cx:c.ox+dx, cy:c.oy+dy});
};
dragStop = function() {
this.data('clone').remove();
};
onDragOver = function(el) {
console.log(el); // displays most of the time the clone
};
elementToDrag.drag(dragMove, dragStart, dragStop);
elementToDrag.onDragOver(onDragOver);

After sleeping a night over it I changed the approach of the clone itself by dragging the original and set a clone at its position. Thus I keep the original position and the onDragOver function shows the correct target element.
dragStart = function() {
var s = this, c = s.clone(); // clone stays at the original position
s.data('clone', c);
s.ox = s.attr('cx');
s.oy = s.attr('cy');
};
dragMove = function(dx, dy) {
var s = this;
s.attr({cx:s.ox+dx, cy:s.oy+dy}); // but now the original is being dragged
};
dragStop = function() {
var c = this.data('clone');
this.attr({cx: c.attr('cx'), cy: c.attr('cy')}); // put original at the position of the clone
this.data('clone').remove(); // and remove the clone
};
onDragOver = function(el) {
console.log(el); // now only the targeted element is shown
};
elementToDrag.drag(dragMove, dragStart, dragStop);
elementToDrag.onDragOver(onDragOver);

Related

IntroJs Hints if parent not Visible

IntroJs hints
How can I skip or hide when a parent element is not visible? For some reason only inline seems to be working for my hints.I have the data-hints in spans on the HTML and I need to check if the nearest element is visible or parent/child element.
var hints = false;
var all = document.getElementsByTagName("*");
function introFunction() {
for (var i = 0, max = all.length; i < max; i++) {
if ((isHidden(all[i]) && hints));
document.getElementById("#helpFunc").html("Show Help");
introJs().hideHints();
} else {
document.getElementById("#helpFunc").html("Hide Help");
introJs().showHints();
}
hints = !hints;
function isHidden(el) {
var style = window.getComputedStyle(el);
return ((style.display === 'none') || (style.visibility === 'hidden'));
}
}
Instead of trying to get the computed style of the element, try checking the element bounding rectangles - if there aren't any, it means the element is not visible.
!!el.getClientRects().length; // false means el or its parent(s) is hidden
LE: that doesn't work for "visibility: hidden;" though. So maybe you can combine the above with what you already have.

Dart print multiple list item at once

How can I type something like "print(list[1,4]);" in Dart?
For example:
int main() {
var products = new List(5);
products[0] = "Laptop";
products[1] = "Mouse";
products[2] = "Keyboard";
products[3] = "Monitor";
products[4] = "Microphone";
print(products[1]); // Mouse
print(products[1,3]); // I want to see 'Mouse,Monitor'
}
This is not directly supported in the SDK but you can easily make a extension on e.g. List to add this feature:
void main() {
final products = List<String>(5);
products[0] = "Laptop";
products[1] = "Mouse";
products[2] = "Keyboard";
products[3] = "Monitor";
products[4] = "Microphone";
print(products[1]); // Mouse
print(products.selectMultiple([1,3]).join(',')); // Mouse,Monitor
}
extension MultiSelectListExtension<E> on List<E> {
Iterable<E> selectMultiple(Iterable<int> indexes) sync* {
for (final index in indexes) {
yield this[index];
}
}
}
You can't make it so [1,3] (as in you own example) would be valid since the [] operator does only allow one argument. So instead, we need to make a method which takes our requested indexes as argument.

Search tree node via closure in Google Apps Script

General problem I'm trying to solve
I'm trying to implement a search tree in Google Apps Script, sorted by pkgName attribute, with the end purpose of comparing imported metadata on a software project against a Sheet containing similar data.
To keep the namespace of the constructor function from being polluted with "private" properties, I used closures.
Implementation
The implementation I have thus far is thus:
SheetDataNode.gs
/**
* Constructor for a SheetDataNode. Takes one, three, or four arguments.
* #param { { package : string, files : { complexity : number, name : string, testingStatus : string }[], rowNumber : number } | string } line data or package name
* #param { string } filename : the files contained in package
* #param { number } complexity : the total number of branches in the file
* #param { number } rowNumber : the row number as this appears in the spreadsheet it is being created from
* #param { string } [ testingStatus ] : the status on the testing of this file. Should be one of the following: NOT_TESTED, FULLY_TESTED, IN_PROGRESS, or PARTIAL
* #returns { SheetDataNode }
* #deprecated This function is not working right now
**/
function SheetDataNode(data, filename, complexity, rowNumber, testingStatus) {
var _pkgName = '';
var _leftChild = null;
var _rightChild = null;
var _beenFound = false;
var _rowNumber = rowNumber;
var _files = [];
// if there's only one argument, it better be an object, having the required fields
if (arguments.length === 1) {
// it should have package field
if ((data.package === undefined) || (data.package !== data.package.toString())) {
throw ReferenceError('only one argument was specified, but it is not an object that contains package');
}
// it should have files field
if ((data.files === undefined) || (!Array.isArray(data.files))) {
throw ReferenceError('Called from the one-arg constructor, so files should be Array');
}
// that files field should itself be an object with the following fields: complexity and name
for (var idx in data.files) {
if (data.files[idx].complexity !== parseInt(data.files[idx].complexity)) {
throw TypeError("complexity should be an integer");
}
if (data.files[idx].name !== data.files[idx].name.toString()) {
throw TypeError("name of file should be a string");
}
}
// sort the array of files
data.files.sort(fileSorter)
// call the initialization function
return SheetDataNode._init(data.package, data.files, parseInt(data.rowNumber));
}
// performing argument checking
if (filename !== filename.toString()) throw TypeError("filename is supposed to be a String")
if ((complexity !== undefined) && (complexity !== parseInt(complexity))) {
throw TypeError("complexity must be a number, or undefined")
}
// call the initialization function, constructing a single file object
return SheetDataNode._init(data.toString(), [{
complexity : complexity,
name: filename,
testingStatus : testingStatus
}])
}
// Helper private function that performs initialization
SheetDataNode._init = function(package, files, rowNumber) {
// bring in the variables
var _pkgName = package;
var _files = files;
var _leftChild = null;
var _rightChild = null;
var _beenFound = false;
var _rowNumber = rowNumber;
// providing a function to add file
_addFile = function(file) {
for (var f in _files) {
if (file.name < _files[f].name) {
_files.splice(f, 0, file)
return
}
}
_files.push(file)
}
return {
getRowNumber : function() { return _rowNumber; },
getPackageName : function () { return _pkgName; },
getFiles: function() { return _files; },
addFile : _addFile,
addFiles : function(files) {
if (!Array.isArray(files)) throw TypeError("files should be an Array")
for (var idx in files) {
_addFile(files[idx])
}
},
getLeftChild : function() { return _leftChild; },
setLeftChild : function(node) {
_leftChild = node;
},
getRightChild : function() { return _rightChild; },
setRightChild : function(node) {
_rightChild = node;
},
insertNode : function(node) {
// set the current node as the head node
var currentNode = this;
// while we are on a non-null node
while (currentNode) {
// if the package of node is the same as that of currentNode
if (currentNode.getPackageName() === node.getPackageName()) {
// simply add the files of node to currentNode._files
currentNode.addFiles(node.getFiles())
return
}
// if the package of node "comes before" that of currentNode, move to the left
if (currentNode.getPackageName() > node.getPackageName()) {
// if the left child of node is defined, that becomes the current node
if (currentNode.getLeftChild()) currentNode = currentNode.getLeftChild()
// else construct it, and we're done
else {
currentNode.setLeftChild(node)
return
}
}
// if the package of node "comes after" that of currentNode, move to the right
if (currentNode.getPackageName() < node.getPackageName()) {
// if the right child of node is defined, that becomes the current node
if (currentNode.getRightChild()) currentNode = currentNode.getRightChild()
// else construct it, and we're done
else {
currentNode.setRightChild(node)
return
}
}
throw Error("Whoa, some infinite looping was about to happen!")
}
}
}
}
UtilityFunctions.gs
/**
* Sorts file objects by their name property, alphabetically
* #param { { name : string } } lvalue
* #param { { name : string } } rvalue
* #returns { boolean } the lexical comparison of lvalue.name,rvalue.name
**/
function fileSorter(lvalue, rvalue) {
if (lvalue.name > rvalue.name) return 1;
return (lvalue.name < rvalue.name) ? -1 : 0;
}
Problem
I'm unit-testing the code, with the failing test case consisting of the following steps :
construct a SheetDataNode node
construct another SheetDataNode otherNode with the same package name as the first, but different filename
insert otherNode into node
expectation: it now has two files
actual: it only has one: the original.
expectation: neither left nor right child nodes were set by this operation
actual : neither left nor right child nodes were set by this operation
The code to do the above looks like this:
QUnit.test("inserting a node having the same package as the node it is assigned to",
function() {
// create the base node
var node = SheetDataNode("example", "main.go", 3, 1)
// insert an other node, with identical package name
var otherNode = SheetDataNode(node.getPackageName(), "logUtility.go", 12, 3)
node.insertNode(otherNode)
// node should contain two files, and neither a left child nor a right child
deepEqual(node.getFiles().map(function(val) {
return val.name
}),
["logUtility.go", "main.go"],
"node contains the right file names")
equal(node.getFiles().length, 2, "A package got added to the node")
ok(!node.getLeftChild(), "leftChild still unset")
ok(!node.getRightChild(), "rightChild still unset")
})
Here is screenshot of the failing assertions:
Remember that the method under test is like this:
insertNode : function(node) {
// set the current node as the head node
var currentNode = this;
// while we are on a non-null node
while (currentNode) {
// if the package of node is the same as that of currentNode
if (currentNode.getPackageName() === node.getPackageName()) {
// simply add the files of node to currentNode._files
currentNode.addFiles(node.getFiles())
return
}
// if the package of node "comes before" that of currentNode, move to the left
if (currentNode.getPackageName() > node.getPackageName()) {
// if the left child of node is defined, that becomes the current node
if (currentNode.getLeftChild()) currentNode = currentNode.getLeftChild()
// else construct it, and we're done
else {
currentNode.setLeftChild(node)
return
}
}
// if the package of node "comes after" that of currentNode, move to the right
if (currentNode.getPackageName() < node.getPackageName()) {
// if the right child of node is defined, that becomes the current node
if (currentNode.getRightChild()) currentNode = currentNode.getRightChild()
// else construct it, and we're done
else {
currentNode.setRightChild(node)
return
}
}
throw Error("Whoa, some infinite looping was about to happen!")
}
The test against the method addFiles, which has this code:
QUnit.test("testing method addFiles",
function() {
// create the base node
var node = SheetDataNode("example", "main.go", 3, 1)
// create an array of files to add
const filesToAdd = [{
name : 'aFile.go',
complexity : 10
}, {
name : 'anotherFile.go',
complexity : 10
}, {
name : 'yetAnotherFile.go',
complexity : 10
}]
// is node.getFiles() an array?!
ok(Array.isArray(node.getFiles()), "node.getFiles() is an array")
// add the files
node.addFiles(filesToAdd)
Logger.log(node.getFiles())
// node.getFiles() should be an Array
ok(Array.isArray(node.getFiles()), "node.getFiles() is still an array")
// node.getFiles should now contain filesToAdd
equal(node.getFiles().length, 1 + filesToAdd.length, "node.getFiles().length increased by the length of the files to add")
})
passes:
, as do the other tests against insertNode, meaning the problem might exist with how we try to reference currentNode in insertNode for array property modification. If so, I have no idea how else to reference, in Google Apps Script, the SheetDataNode to undergo state change
I was able to solve the problem, with inspiration from the MDN docs on closures, by changing the private function property declaration from :
_addFile = function(file) {
for (var f in _files) {
if (file.name < _files[f].name) {
_files.splice(f, 0, file)
return
}
}
_files.push(file)
}
to
function _addFile(file) {
for (var f in _files) {
if (file.name < _files[f].name) {
_files.splice(f, 0, file)
return
}
}
_files.push(file)
}
idk why this works, because I forgot the difference between declaring method like a function variable (what I was doing), and preceding the name of the method with function like it's any other function. I'll have to (re-)learn that...

Simple issue - How to access a variable from a 'class' inside a separate 'struct'?

I am new to C++/JUCE. I have been working to get a basic synth running and just testing some things out to learn the ropes.
It’s working fine already. But I’m still just learning my way around C++/JUCE and how to declare or access classes/objects/variables.
I’m trying to make a modification to something that I’m stuck with.
I have the following (just excerpts to demonstrate)…
This is where the synthesizer level is set:
struct SineWaveVoice : public SynthesiserVoice
{
SineWaveVoice() {}
bool canPlaySound (SynthesiserSound* sound) override
{
return dynamic_cast<SineWaveSound*> (sound) != nullptr;
}
void startNote (int midiNoteNumber, float velocity,
SynthesiserSound*, int /*currentPitchWheelPosition*/) override
{
currentAngle = 0.0;
level = velocity * 0.15;
tailOff = 0.0;
Ie. Level is set by velocity * 0.15.
In my test set up, I already have a level knob defined under MainContentComponent like this:
class MainContentComponent : public AudioAppComponent,
private Timer
{
public:
MainContentComponent()
: synthAudioSource(keyboardState),
keyboardComponent(keyboardState, MidiKeyboardComponent::horizontalKeyboard)
{
LabeledSlider* control = new LabeledSlider("Frequency");
control->slider.setRange(20.0, 20000.0);
control->slider.setSkewFactorFromMidPoint(500.0);
control->slider.setNumDecimalPlacesToDisplay(1);
control->slider.setValue(currentFrequency, dontSendNotification);
control->slider.onValueChange = [this] { targetFrequency = frequency.slider.getValue(); };
control->slider.setTextBoxStyle(Slider::TextBoxBelow, false, 100, 20);
control->slider.setRange(50.0, 5000.0);
control->slider.setSkewFactorFromMidPoint(500.0);
control->slider.setNumDecimalPlacesToDisplay(1);
addAndMakeVisible(knobs.add(control));
control = new LabeledSlider("Level");
control->slider.setRange(0.0, 1.0);
control->slider.onValueChange = [this] { targetLevel = (float)level.slider.getValue(); };
addAndMakeVisible(knobs.add(control));
....
private:
{
float currentLevel = 0.1f, targetLevel = 0.1f;
LabeledSlider level{ "Level" };
So let’s say I want to use this level slider variable “targetLevel” to be multiplied by the velocity in the “struct” above instead of 0.15.
What do I need to type up there to be able to access and use “targetLevel”? I tried multiple things but I can’t quite figure it out.
Thanks
I am assuming that your SineWaveVoice lies within your SynthAudioSource class and that the voice is a part of a Synthesizer object. To access anything within your SineWaveVoice struct from MainContentComponent you need to expose this somehow via the SynthAudioSource. So my suggestion is that in your SynthAudioSource add a method like this:
void setLevel(double lvl)
{
for (auto i=0; i<synth.getNumVoices(); i++)
{
SineWaveVoice *v = dynamic_cast<SineWaveVoice *>(synth.getVoice(i));
v->level = lvl * v->velocity;
}
}
Then to access this in your MainContentComponent you just do this:
control->slider.onValueChange = [this] {
targetLevel = (float)level.slider.getValue();
synthAudioSource.setLevel(targetLevel);
};
However, notice that this value will be overwritten every time you get a new startNote event. So you should probably store a copy of target level in your SineWaveVoice and multiply with that rather than 0.15.

OSMdroid bounds marker

////OSMdroid centered on the markers////
I add markers, I need to map the maximum increases or decreases in such a way that all markers were visible
my code:
public class mapcode extends Activity {
globalvar appState;
int stats=0;
private MapView mapView;
private IMapController mapController;
private SimpleLocationOverlay mMyLocationOverlay;
private ScaleBarOverlay mScaleBarOverlay;
ItemizedIconOverlay<OverlayItem> currentLocationOverlay;
DefaultResourceProxyImpl resourceProxy;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.map);
appState = ((globalvar) getApplicationContext());
mapView = (MapView) this.findViewById(R.id.mapview);
mapView.setTileSource(TileSourceFactory.MAPNIK);
// mapView.setBuiltInZoomControls(true); //кнопка ZOOM +-
mapView.setMultiTouchControls(true);
mapController = this.mapView.getController();
mapController.setZoom(2);
this.mMyLocationOverlay = new SimpleLocationOverlay(this);
this.mapView.getOverlays().add(mMyLocationOverlay);
this.mScaleBarOverlay = new ScaleBarOverlay(this);
this.mapView.getOverlays().add(mScaleBarOverlay);
// this.mapView
/////////////////
resourceProxy = new DefaultResourceProxyImpl(getApplicationContext());
GeoPoint currentLocation = new GeoPoint(55.860863,37.115046);
GeoPoint currentLocation2 = new GeoPoint(63.557413,-156.102119);
OverlayItem myLocationOverlayItem = new OverlayItem("Here", "Current Position", currentLocation);
Drawable myCurrentLocationMarker = this.getResources().getDrawable(R.drawable.a);
myLocationOverlayItem.setMarker(myCurrentLocationMarker);
// myLocationOverlayItem.setMarkerHotspot(HotspotPlace.CENTER); //no working/
final ArrayList<OverlayItem> items = new ArrayList<OverlayItem>();
items.add(myLocationOverlayItem);
myLocationOverlayItem = new OverlayItem("Here", "Current Position", currentLocation2);
myCurrentLocationMarker = this.getResources().getDrawable(R.drawable.a);
myLocationOverlayItem.setMarker(myCurrentLocationMarker);
// myLocationOverlayItem.setMarkerHotspot(HotspotPlace.CENTER); // no working
items.add(myLocationOverlayItem);
currentLocationOverlay = new ItemizedIconOverlay<OverlayItem>(items,
new ItemizedIconOverlay.OnItemGestureListener<OverlayItem>() {
public boolean onItemSingleTapUp(final int index, final OverlayItem item) {
return true;
}
public boolean onItemLongPress(final int index, final OverlayItem item) {
return true;
}
}, resourceProxy);
this.mapView.getOverlays().add(this.currentLocationOverlay);
}
I added two markers, but only one is visible:
and I need to osmdroid is centered and immediately showed both marker
I think you want something like this:
int minLat = Integer.MAX_VALUE;
int maxLat = Integer.MIN_VALUE;
int minLong = Integer.MAX_VALUE;
int maxLong = Integer.MIN_VALUE;
ArrayList<OverlayItem> items = new ArrayList<OverlayItem>();
for (OverlayItem item : items) {
GeoPoint point = item.getPoint();
if (point.getLatitudeE6() < minLat)
minLat = point.getLatitudeE6();
if (point.getLatitudeE6() > maxLat)
maxLat = point.getLatitudeE6();
if (point.getLongitudeE6() < minLong)
minLong = point.getLongitudeE6();
if (point.getLongitudeE6() > maxLong)
maxLong = point.getLongitudeE6();
}
BoundingBoxE6 boundingBox = new BoundingBoxE6(maxLat, maxLong, minLat, minLong);
mMapView.zoomToBoundingBox(boundingBox);
You can calculate boundingBox by BoundingBox.fromGeoPoints(geoPoints)
fun zoomToBounds(points: List<LatLng>) {
val geoPoints = points.map { GeoPoint(it.latitude, it.longitude) }
val boundingBox = BoundingBox.fromGeoPoints(geoPoints)
mapView.zoomToBoundingBox(boundingBox, true)
}
It is also possible to have some paddings by using zoomtoBoundingBox overloaded method and setting the pBorderSizeInPixels parameter
public double zoomToBoundingBox(
final BoundingBox pBoundingBox,
final boolean pAnimated,
final int pBorderSizeInPixels,
final double pMaximumZoom,
final Long pAnimationSpeed
)