When an Excel cell referencing other cells is selected, the referenced cells are systematically highlighted with different colours. I would like to imitate and reproduce this effect in JavaScript and CSS.
For instance, in the beginning the background colour of Cell A1 is gray:
Once we double click on Cell C2, its referenced cells are highlighted:
We only learn the background colours (and ignore the border colours). A3 now is in purple; A2 is in purple on top of red; A1 is in purple on top of red on top of blue on top of gray.
Does anyone know how this colour effect is called (eg, overlay, hover)? Is there a notion of opacity there? Given the colour code of purple and red (and maybe an opacity number), is there an easy way in JavaScript and CSS to produce the colour of A3?
The only thing I can think of is by using svg and rectangles, dynamically generating them and assigning them colors based on numbers of cells selected (I suppose Excel assigns random colors?!). You can achieve the overlay effect by using mix-blend-mode (see snippet below, pay attention to the colors defined and the colors displayed).
.multiply {
background: white;
}
.multiply rect {
mix-blend-mode: multiply;
}
<svg class="multiply" width="400" height="500">
<rect fill="cyan" width="150" height="20" x="0" y="0" />
<rect fill="yellow" width="100" height="40" x="50" y="0" />
<rect fill="magenta" width="50" height="60" x="100" y="0" />
</svg>
Another way you can do it (this is more Javascript oriented) is to compute the RGB value of the colors you want to combine and then by using the R, G and B values create the overlayed color, see link
Related
I'm using D3.js. I created a text element in svg.
I have a element.
<text id="text16" class="text" x="xx" y="yy"
transform="translate(tx,ty)" height="hh"
text-anchor="left"">DC_AAA_BBB_CCC_XXXX</text>
I want to reduce set the width. And when the text element width is smaller that the raw text's length(calculated from .getComputedTextLength), I want it to show up to the text element width. Such that only up to "DC_AAA_BBB_" is shown when raw text length is longer.
I've tried adding css -> width: 100px;
Also tried adding width attribute in DOM -> width="100px"
Both did not work. How can I achieve this? Thanks!
You can use clip-path to clip to whatever shape you want, see e.g masking-path-01 from the svg testsuite.
Relevant parts, defining the clip path:
<clipPath id="clip1">
<rect x="200" y="10" width="60" height="100"/>
... you can have any shapes you want here ...
</clipPath>
and then apply the clip path like this:
<g clip-path="url(#clip1)">
... your text elements here ...
</g>
I'm drawing a chart in D3.js, and I'm using a <rect> as the actual charting area (lines, plots, etc.). The plan is to only append the path to the <rect> such that it doesn't overflow the charting zone when user drags around. Right now it looks like this:
But when I tried to do:
var path = rect.append('path').attr(...)
The path itself doesn't even show up. The original version is just to append path to svg, whic works:
var path = svg.append('path').attr(...)
I also cannot do overflow:hidden like regular HTML elements because path is not contained inside the rect.
If appending path to rect is not possible or recommended, what is the best way to limit the "activity area" of path so that it doesn't cause overflow?
The reason that you can't see the path inside the rect is because SVG rect elements don't support having child elements, they aren't containers.
What you need to do is include an g (group) element which is a container and instead place both your rect and your path inside it. This is how a large number of D3 examples work because it means you can interact with the group, instead of all the individual sub-elements, which is great if you're zooming/moving things around.
In your case if you don't want you're line to be visible outside of the rect then you can simply omit drawing those points in the first place, or clip them once you have drawn them using a clip path.
I've put together a small example to illustrate using a clip-path with a rectangle which matches your use case. The blue stroke illustrates the area that would be filled without a clip-path. Once the clip-path has been applied however, you can see the actual filled area is much smaller than the full definition of the rectangle.
.fill {
fill: steelblue;
}
.outline {
stroke: steelblue;
fill: none;
}
<svg width="300" height="300">
<defs>
<clipPath id="demoClip">
<rect x="30" y="0" height="100" width="100"/>
</clipPath>
</defs>
<rect class="fill" x="0" y="0" width="200" height="200" clip-path="url(#demoClip)"/>
<rect class="outline" x="0" y="0" width="200" height="200"/>
</svg>
On desktop onmouseover it changes color to green and then I click it changes to red but in mobile devices both event goes at the same time. Is it possible to make on tap changes to green color then on 2nd tap it goes to red color?
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="800" height="600" version="1.1" style="display:inline">
<g>
<rect id="rect1" x="160" y="10"
width="60" height="60" fill="blue"
onmouseout="evt.target.setAttribute('fill','blue');"
onclick="evt.target.setAttribute('fill','red');"
onmouseover="evt.target.setAttribute('fill','green');"/>
</g>
</svg>
fiddel
thanks!
The right behavior on touch devices usability-wise would be to color the rect green when the touch starts, if the user drags the finger off the rect then it would go back to blue. If the user releases at the same target it would change the color to red. This behavior could be replicated with CSS (removing your onmouseout and onmouseover handlers):
rect {
fill: blue;
}
rect:active {
fill: green
}
Now, if you really want it to behave in the way you describe (first tap is green, second tap is red) then you'd have to keep the state somewhere (in the DOM?) which complicates things, from the top of my mind I'd try...
ontouchend="evt.target.getAttribute('data-clicked') === "true" ? evt.target.setAttributed('fill', 'red') : evt.target.setAttribute('data-clicked', 'true')";
The problem with this is that you can start the touch at a different point and end the touch at the rect element.
I just started reading about svg and I came up with the following question
I am creating a simple svg with a text inside as shown below.
From my reading I understood that x and y of the text tag declares the position of the text inside the svg space.
Why when I set both x and y to 0 the text does not appear and when I change x and y to 10 for example it is displayed? Isn't x=0 and y=0 meaning the top left corner of the svg tag?
Thanks
<svg width="200" height="100">
<text x="0" y="0">hello</text>
</svg>
You're correct, (0,0) is indeed the top left corner of the SVG area (at least before you start transforming the coordinates).
However, your text element <text x="0" y="0">hello</text> is positioned with the leftmost end of its baseline at (0,0), which means the text will appear entirely off the top of the SVG image.
Try this: change your text tag to <text x="0" y="0">goodbye</text>. You should now be able to see the descending parts of the 'g' and 'y' at the top of your SVG.
You can shift your text down by one line if you provide a y coordinate equal to the line height, for example:
<svg width="200" height="100">
<text x="0" y="1em">hello</text>
</svg>
Here's a JSFiddle link for you to play with.
To make <text> behave in a more standard way, you can use dominant-baseline: hanging like so:
<text x="0" style="dominant-baseline: hanging;">Hello</text>
You can see examples of different values of this property here.
This is my first SVG project, and I’m not a programmer, but I dabble in interactive infographics. My previous experience in this area comes from working with ActionScript.
I’m using plain SVG (no Raphael, D3, etc.) and trying to create an interactive barchart. After some initial difficulty with the SVG coordinate system and scaling, I found some code online that handles the postscaling translation:
<text x="x_coord0" y="y_coord0" transform="scale(x_scale, y_scale) translate(-x_coord0*(x_scale-1)/x_scale, -y_coord0*(y_scale-1)/y_scale)" …>text</text>
And I converted it into this JavaScript:
var translationfactor = ((0 - y_position)*(y_scalefactor - 1) / y_scalefactor);
var matrix = "scale(1," + y_scalefactor + ") translate(0," + Number(translationfactor) + ")";
targetbar.setAttribute("transform", matrix);
The problem is that I need the bars “translated” back to the chart’s baseline, not the original locations of their topmost points. Currently the correctly scaled bars are hugging the top of the chart:
http://billgregg.net/miscellany/upsidedown-barchart.png
I’ve tried several fixes, including plugging the bars’ ”missing height” into translationfactor (the bars start out the full height of the chart and get scaled down dynamically). Nothing has worked. Part of my problem is that, besides being new to SVGs, I can stare at that code all day and my brain still can’t parse it. Multiplying negative numbers is too abstract and at a fundamental level I just don’t “get” the math, which of course makes modifying the code difficult.
My questions:
(1) What’s the fix for the code above to position the bars back on the baseline of the chart?
(2) Is there a more transparent, more pedestrian way of accomplishing the translation? My first thought along these lines was that if a bar’s height is reduced to 40% of its original value, then multiplying the original Y coordinate value by 250% should reset the bar to its original location (at least its topmost point), but that doesn’t seem to work.
(3) Is there a way to set a bar’s point of origin to its bottom? In Flash it’s possible, though as far as I know it’s a manual, not a programmatic task.
(4) Is there a method similar to .localToGlobal() in ActionScript that would allow me to avoid having to mess with the local coordinate system at all?
Behind the scenes there is matrix math going on and it can be hard to get your head around the pre and post multiplication of arrays.
It's not entirely clear what you are trying to achieve, but reading between the lines, it sounds like you are wanting to provide graph coordinates in their raw(ish) form and have the SVG scale and position them for you(?)
If that's the case, then I think the solution is simpler than what you think.
Assuming I'm right, we'll start with something that looks like this:
<?xml version="1.0" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<g transform="">
<rect x="0" width="1" height="5" fill="red"/>
<rect x="1" width="1" height="11" fill="green"/>
<rect x="2" width="1" height="12" fill="orange"/>
<rect x="3" width="1" height="8" fill="blue"/>
</g>
</svg>
Where x is obvious and the bar length is in height. y defaults to 0, so we don't need it here.
You basically want to know what goes in the transform to scale and position the bars on your page. The fact that your graph is "upside-down" helps a little. Because the origin in an SVG is at the top left.
First apply a scale. Let's make the bars 20 pixels wide, and scale the lengths up by 10.
<g transform="scale(20,10)">
Next you want to position the graph on the page. Let's put the top-left corner at (40,40).
In SVG the transformations are concatenated in order (post-multiplied) so in order for the translation to be what you specify and not be multiplied by the scale, you should put it first.
<g transform="translate(40,40) scale(20,10)">
So the final SVG looks like this:
<?xml version="1.0" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
<g transform="translate(40,40) scale(20,10)">
<rect x="0" width="1" height="5" fill="red"/>
<rect x="1" width="1" height="11" fill="green"/>
<rect x="2" width="1" height="12" fill="orange"/>
<rect x="3" width="1" height="8" fill="blue"/>
</g>
</svg>
The above has been simplified by assuming you have already subtracted the values from your base 20%. If you wanted to keep the pure raw values, it's possible, but things get a bit trickier. You would need to either tinker with both the y and height value of each bar, or use clipping to hide the part of the bar above 20%.
For "right way up"/normal graphs. All you need to do is make the y scale negative and translate the graph so that the bottom-left is where you want it.
<g transform="translate(40,140) scale(20,-10)">
Hope this helps.